set svn:eol-style to native
[reactos.git] / reactos / lib / ole32 / storage32.c
index d88d680..249c766 100644 (file)
-/*\r
- * Compound Storage (32 bit version)\r
- * Storage implementation\r
- *\r
- * This file contains the compound file implementation\r
- * of the storage interface.\r
- *\r
- * Copyright 1999 Francis Beaudet\r
- * Copyright 1999 Sylvain St-Germain\r
- * Copyright 1999 Thuy Nguyen\r
- * Copyright 2005 Mike McCormack\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- */\r
-\r
-#include <assert.h>\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-#define COBJMACROS\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "winnls.h"\r
-#include "winuser.h"\r
-#include "wine/unicode.h"\r
-#include "wine/debug.h"\r
-\r
-#include "storage32.h"\r
-#include "ole2.h"      /* For Write/ReadClassStm */\r
-\r
-#include "winreg.h"\r
-#include "wine/wingdi16.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(storage);\r
-\r
-#define FILE_BEGIN 0\r
-\r
-/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */\r
-#define OLESTREAM_ID 0x501\r
-#define OLESTREAM_MAX_STR_LEN 255\r
-\r
-static const char rootPropertyName[] = "Root Entry";\r
-\r
-\r
-/* OLESTREAM memory structure to use for Get and Put Routines */\r
-/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */\r
-typedef struct\r
-{\r
-    DWORD dwOleID;\r
-    DWORD dwTypeID;\r
-    DWORD dwOleTypeNameLength;\r
-    CHAR  strOleTypeName[OLESTREAM_MAX_STR_LEN];\r
-    CHAR  *pstrOleObjFileName;\r
-    DWORD dwOleObjFileNameLength;\r
-    DWORD dwMetaFileWidth;\r
-    DWORD dwMetaFileHeight;\r
-    CHAR  strUnknown[8]; /* don't know what is this 8 byts information in OLE stream. */\r
-    DWORD dwDataLength;\r
-    BYTE *pData;\r
-}OLECONVERT_OLESTREAM_DATA;\r
-\r
-/* CompObj Stream structure */\r
-/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */\r
-typedef struct\r
-{\r
-    BYTE byUnknown1[12];\r
-    CLSID clsid;\r
-    DWORD dwCLSIDNameLength;\r
-    CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];\r
-    DWORD dwOleTypeNameLength;\r
-    CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];\r
-    DWORD dwProgIDNameLength;\r
-    CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];\r
-    BYTE byUnknown2[16];\r
-}OLECONVERT_ISTORAGE_COMPOBJ;\r
-\r
-\r
-/* Ole Presention Stream structure */\r
-/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */\r
-typedef struct\r
-{\r
-    BYTE byUnknown1[28];\r
-    DWORD dwExtentX;\r
-    DWORD dwExtentY;\r
-    DWORD dwSize;\r
-    BYTE *pData;\r
-}OLECONVERT_ISTORAGE_OLEPRES;\r
-\r
-\r
-\r
-/***********************************************************************\r
- * Forward declaration of internal functions used by the method DestroyElement\r
- */\r
-static HRESULT deleteStorageProperty(\r
-  StorageImpl *parentStorage,\r
-  ULONG        foundPropertyIndexToDelete,\r
-  StgProperty  propertyToDelete);\r
-\r
-static HRESULT deleteStreamProperty(\r
-  StorageImpl *parentStorage,\r
-  ULONG         foundPropertyIndexToDelete,\r
-  StgProperty   propertyToDelete);\r
-\r
-static HRESULT findPlaceholder(\r
-  StorageImpl *storage,\r
-  ULONG         propertyIndexToStore,\r
-  ULONG         storagePropertyIndex,\r
-  INT         typeOfRelation);\r
-\r
-static HRESULT adjustPropertyChain(\r
-  StorageImpl *This,\r
-  StgProperty   propertyToDelete,\r
-  StgProperty   parentProperty,\r
-  ULONG         parentPropertyId,\r
-  INT         typeOfRelation);\r
-\r
-/***********************************************************************\r
- * Declaration of the functions used to manipulate StgProperty\r
- */\r
-\r
-static ULONG getFreeProperty(\r
-  StorageImpl *storage);\r
-\r
-static void updatePropertyChain(\r
-  StorageImpl *storage,\r
-  ULONG       newPropertyIndex,\r
-  StgProperty newProperty);\r
-\r
-static LONG propertyNameCmp(\r
-    const OLECHAR *newProperty,\r
-    const OLECHAR *currentProperty);\r
-\r
-\r
-/***********************************************************************\r
- * Declaration of miscellaneous functions...\r
- */\r
-static HRESULT validateSTGM(DWORD stgmValue);\r
-\r
-static DWORD GetShareModeFromSTGM(DWORD stgm);\r
-static DWORD GetAccessModeFromSTGM(DWORD stgm);\r
-static DWORD GetCreationModeFromSTGM(DWORD stgm);\r
-\r
-extern IPropertySetStorageVtbl IPropertySetStorage_Vtbl;\r
-\r
-\r
-\r
-/************************************************************************\r
-** Storage32BaseImpl implementatiion\r
-*/\r
-\r
-/************************************************************************\r
- * Storage32BaseImpl_QueryInterface (IUnknown)\r
- *\r
- * This method implements the common QueryInterface for all IStorage32\r
- * implementations contained in this file.\r
- *\r
- * See Windows documentation for more details on IUnknown methods.\r
- */\r
-HRESULT WINAPI StorageBaseImpl_QueryInterface(\r
-  IStorage*        iface,\r
-  REFIID             riid,\r
-  void**             ppvObject)\r
-{\r
-  StorageBaseImpl *This = (StorageBaseImpl *)iface;\r
-  /*\r
-   * Perform a sanity check on the parameters.\r
-   */\r
-  if ( (This==0) || (ppvObject==0) )\r
-    return E_INVALIDARG;\r
-\r
-  /*\r
-   * Initialize the return parameter.\r
-   */\r
-  *ppvObject = 0;\r
-\r
-  /*\r
-   * Compare the riid with the interface IDs implemented by this object.\r
-   */\r
-  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)\r
-  {\r
-    *ppvObject = (IStorage*)This;\r
-  }\r
-  else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)\r
-  {\r
-    *ppvObject = (IStorage*)This;\r
-  }\r
-  else if (memcmp(&IID_IPropertySetStorage, riid, sizeof(IID_IPropertySetStorage)) == 0)\r
-  {\r
-    *ppvObject = (IStorage*)&This->pssVtbl;\r
-  }\r
-\r
-  /*\r
-   * Check that we obtained an interface.\r
-   */\r
-  if ((*ppvObject)==0)\r
-    return E_NOINTERFACE;\r
-\r
-  /*\r
-   * Query Interface always increases the reference count by one when it is\r
-   * successful\r
-   */\r
-  IStorage_AddRef(iface);\r
-\r
-  return S_OK;\r
-}\r
-\r
-/************************************************************************\r
- * Storage32BaseImpl_AddRef (IUnknown)\r
- *\r
- * This method implements the common AddRef for all IStorage32\r
- * implementations contained in this file.\r
- *\r
- * See Windows documentation for more details on IUnknown methods.\r
- */\r
-ULONG WINAPI StorageBaseImpl_AddRef(\r
-            IStorage* iface)\r
-{\r
-  StorageBaseImpl *This = (StorageBaseImpl *)iface;\r
-  ULONG ref = InterlockedIncrement(&This->ref);\r
-\r
-  TRACE("(%p) AddRef to %ld\n", This, ref);\r
-\r
-  return ref;\r
-}\r
-\r
-/************************************************************************\r
- * Storage32BaseImpl_Release (IUnknown)\r
- *\r
- * This method implements the common Release for all IStorage32\r
- * implementations contained in this file.\r
- *\r
- * See Windows documentation for more details on IUnknown methods.\r
- */\r
-ULONG WINAPI StorageBaseImpl_Release(\r
-      IStorage* iface)\r
-{\r
-  StorageBaseImpl *This = (StorageBaseImpl *)iface;\r
-  /*\r
-   * Decrease the reference count on this object.\r
-   */\r
-  ULONG ref = InterlockedDecrement(&This->ref);\r
-\r
-  TRACE("(%p) ReleaseRef to %ld\n", This, ref);\r
-\r
-  /*\r
-   * If the reference count goes down to 0, perform suicide.\r
-   */\r
-  if (ref == 0)\r
-  {\r
-    /*\r
-     * Since we are using a system of base-classes, we want to call the\r
-     * destructor of the appropriate derived class. To do this, we are\r
-     * using virtual functions to implement the destructor.\r
-     */\r
-    This->v_destructor(This);\r
-  }\r
-\r
-  return ref;\r
-}\r
-\r
-/************************************************************************\r
- * Storage32BaseImpl_OpenStream (IStorage)\r
- *\r
- * This method will open the specified stream object from the current storage.\r
- *\r
- * See Windows documentation for more details on IStorage methods.\r
- */\r
-HRESULT WINAPI StorageBaseImpl_OpenStream(\r
-  IStorage*        iface,\r
-  const OLECHAR*   pwcsName,  /* [string][in] */\r
-  void*            reserved1, /* [unique][in] */\r
-  DWORD            grfMode,   /* [in]  */\r
-  DWORD            reserved2, /* [in]  */\r
-  IStream**        ppstm)     /* [out] */\r
-{\r
-  StorageBaseImpl *This = (StorageBaseImpl *)iface;\r
-  IEnumSTATSTGImpl* propertyEnumeration;\r
-  StgStreamImpl*    newStream;\r
-  StgProperty       currentProperty;\r
-  ULONG             foundPropertyIndex;\r
-  HRESULT           res = STG_E_UNKNOWN;\r
-  DWORD             parent_grfMode;\r
-\r
-  TRACE("(%p, %s, %p, %lx, %ld, %p)\n",\r
-       iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);\r
-\r
-  /*\r
-   * Perform a sanity check on the parameters.\r
-   */\r
-  if ( (pwcsName==NULL) || (ppstm==0) )\r
-  {\r
-    res = E_INVALIDARG;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Initialize the out parameter\r
-   */\r
-  *ppstm = NULL;\r
-\r
-  /*\r
-   * Validate the STGM flags\r
-   */\r
-  if ( FAILED( validateSTGM(grfMode) ))\r
-  {\r
-    res = STG_E_INVALIDFLAG;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * As documented.\r
-   */\r
-  if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||\r
-        (grfMode & STGM_DELETEONRELEASE) ||\r
-        (grfMode & STGM_TRANSACTED) )\r
-  {\r
-    res = STG_E_INVALIDFUNCTION;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Check that we're compatible with the parent's storage mode\r
-   */\r
-  parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags );\r
-  if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) )\r
-  {\r
-    res = STG_E_ACCESSDENIED;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Create a property enumeration to search the properties\r
-   */\r
-  propertyEnumeration = IEnumSTATSTGImpl_Construct(\r
-    This->ancestorStorage,\r
-    This->rootPropertySetIndex);\r
-\r
-  /*\r
-   * Search the enumeration for the property with the given name\r
-   */\r
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(\r
-    propertyEnumeration,\r
-    pwcsName,\r
-    &currentProperty);\r
-\r
-  /*\r
-   * Delete the property enumeration since we don't need it anymore\r
-   */\r
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);\r
-\r
-  /*\r
-   * If it was found, construct the stream object and return a pointer to it.\r
-   */\r
-  if ( (foundPropertyIndex!=PROPERTY_NULL) &&\r
-       (currentProperty.propertyType==PROPTYPE_STREAM) )\r
-  {\r
-    newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);\r
-\r
-    if (newStream!=0)\r
-    {\r
-      newStream->grfMode = grfMode;\r
-      *ppstm = (IStream*)newStream;\r
-\r
-      /*\r
-       * Since we are returning a pointer to the interface, we have to\r
-       * nail down the reference.\r
-       */\r
-      IStream_AddRef(*ppstm);\r
-\r
-      res = S_OK;\r
-      goto end;\r
-    }\r
-\r
-    res = E_OUTOFMEMORY;\r
-    goto end;\r
-  }\r
-\r
-  res = STG_E_FILENOTFOUND;\r
-\r
-end:\r
-  if (res == S_OK)\r
-    TRACE("<-- IStream %p\n", *ppstm);\r
-  TRACE("<-- %08lx\n", res);\r
-  return res;\r
-}\r
-\r
-/************************************************************************\r
- * Storage32BaseImpl_OpenStorage (IStorage)\r
- *\r
- * This method will open a new storage object from the current storage.\r
- *\r
- * See Windows documentation for more details on IStorage methods.\r
- */\r
-HRESULT WINAPI StorageBaseImpl_OpenStorage(\r
-  IStorage*        iface,\r
-  const OLECHAR*   pwcsName,      /* [string][unique][in] */\r
-  IStorage*        pstgPriority,  /* [unique][in] */\r
-  DWORD            grfMode,       /* [in] */\r
-  SNB              snbExclude,    /* [unique][in] */\r
-  DWORD            reserved,      /* [in] */\r
-  IStorage**       ppstg)         /* [out] */\r
-{\r
-  StorageBaseImpl *This = (StorageBaseImpl *)iface;\r
-  StorageInternalImpl* newStorage;\r
-  IEnumSTATSTGImpl*      propertyEnumeration;\r
-  StgProperty            currentProperty;\r
-  ULONG                  foundPropertyIndex;\r
-  HRESULT                res = STG_E_UNKNOWN;\r
-  DWORD                  parent_grfMode;\r
-\r
-  TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",\r
-       iface, debugstr_w(pwcsName), pstgPriority,\r
-       grfMode, snbExclude, reserved, ppstg);\r
-\r
-  /*\r
-   * Perform a sanity check on the parameters.\r
-   */\r
-  if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )\r
-  {\r
-    res = E_INVALIDARG;\r
-    goto end;\r
-  }\r
-\r
-  /* as documented */\r
-  if (snbExclude != NULL)\r
-  {\r
-    res = STG_E_INVALIDPARAMETER;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Validate the STGM flags\r
-   */\r
-  if ( FAILED( validateSTGM(grfMode) ))\r
-  {\r
-    res = STG_E_INVALIDFLAG;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * As documented.\r
-   */\r
-  if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||\r
-        (grfMode & STGM_DELETEONRELEASE) ||\r
-        (grfMode & STGM_PRIORITY) )\r
-  {\r
-    res = STG_E_INVALIDFUNCTION;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Check that we're compatible with the parent's storage mode\r
-   */\r
-  parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags );\r
-  if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) )\r
-  {\r
-    res = STG_E_ACCESSDENIED;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Initialize the out parameter\r
-   */\r
-  *ppstg = NULL;\r
-\r
-  /*\r
-   * Create a property enumeration to search the properties\r
-   */\r
-  propertyEnumeration = IEnumSTATSTGImpl_Construct(\r
-                          This->ancestorStorage,\r
-                          This->rootPropertySetIndex);\r
-\r
-  /*\r
-   * Search the enumeration for the property with the given name\r
-   */\r
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(\r
-                         propertyEnumeration,\r
-                         pwcsName,\r
-                         &currentProperty);\r
-\r
-  /*\r
-   * Delete the property enumeration since we don't need it anymore\r
-   */\r
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);\r
-\r
-  /*\r
-   * If it was found, construct the stream object and return a pointer to it.\r
-   */\r
-  if ( (foundPropertyIndex!=PROPERTY_NULL) &&\r
-       (currentProperty.propertyType==PROPTYPE_STORAGE) )\r
-  {\r
-    /*\r
-     * Construct a new Storage object\r
-     */\r
-    newStorage = StorageInternalImpl_Construct(\r
-                   This->ancestorStorage,\r
-                   grfMode,\r
-                   foundPropertyIndex);\r
-\r
-    if (newStorage != 0)\r
-    {\r
-      *ppstg = (IStorage*)newStorage;\r
-\r
-      /*\r
-       * Since we are returning a pointer to the interface,\r
-       * we have to nail down the reference.\r
-       */\r
-      StorageBaseImpl_AddRef(*ppstg);\r
-\r
-      res = S_OK;\r
-      goto end;\r
-    }\r
-\r
-    res = STG_E_INSUFFICIENTMEMORY;\r
-    goto end;\r
-  }\r
-\r
-  res = STG_E_FILENOTFOUND;\r
-\r
-end:\r
-  TRACE("<-- %08lx\n", res);\r
-  return res;\r
-}\r
-\r
-/************************************************************************\r
- * Storage32BaseImpl_EnumElements (IStorage)\r
- *\r
- * This method will create an enumerator object that can be used to\r
- * retrieve informatino about all the properties in the storage object.\r
- *\r
- * See Windows documentation for more details on IStorage methods.\r
- */\r
-HRESULT WINAPI StorageBaseImpl_EnumElements(\r
-  IStorage*       iface,\r
-  DWORD           reserved1, /* [in] */\r
-  void*           reserved2, /* [size_is][unique][in] */\r
-  DWORD           reserved3, /* [in] */\r
-  IEnumSTATSTG**  ppenum)    /* [out] */\r
-{\r
-  StorageBaseImpl *This = (StorageBaseImpl *)iface;\r
-  IEnumSTATSTGImpl* newEnum;\r
-\r
-  TRACE("(%p, %ld, %p, %ld, %p)\n",\r
-       iface, reserved1, reserved2, reserved3, ppenum);\r
-\r
-  /*\r
-   * Perform a sanity check on the parameters.\r
-   */\r
-  if ( (This==0) || (ppenum==0))\r
-    return E_INVALIDARG;\r
-\r
-  /*\r
-   * Construct the enumerator.\r
-   */\r
-  newEnum = IEnumSTATSTGImpl_Construct(\r
-              This->ancestorStorage,\r
-              This->rootPropertySetIndex);\r
-\r
-  if (newEnum!=0)\r
-  {\r
-    *ppenum = (IEnumSTATSTG*)newEnum;\r
-\r
-    /*\r
-     * Don't forget to nail down a reference to the new object before\r
-     * returning it.\r
-     */\r
-    IEnumSTATSTG_AddRef(*ppenum);\r
-\r
-    return S_OK;\r
-  }\r
-\r
-  return E_OUTOFMEMORY;\r
-}\r
-\r
-/************************************************************************\r
- * Storage32BaseImpl_Stat (IStorage)\r
- *\r
- * This method will retrieve information about this storage object.\r
- *\r
- * See Windows documentation for more details on IStorage methods.\r
- */\r
-HRESULT WINAPI StorageBaseImpl_Stat(\r
-  IStorage*        iface,\r
-  STATSTG*         pstatstg,     /* [out] */\r
-  DWORD            grfStatFlag)  /* [in] */\r
-{\r
-  StorageBaseImpl *This = (StorageBaseImpl *)iface;\r
-  StgProperty    curProperty;\r
-  BOOL           readSuccessful;\r
-  HRESULT        res = STG_E_UNKNOWN;\r
-\r
-  TRACE("(%p, %p, %lx)\n",\r
-       iface, pstatstg, grfStatFlag);\r
-\r
-  /*\r
-   * Perform a sanity check on the parameters.\r
-   */\r
-  if ( (This==0) || (pstatstg==0))\r
-  {\r
-    res = E_INVALIDARG;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Read the information from the property.\r
-   */\r
-  readSuccessful = StorageImpl_ReadProperty(\r
-                    This->ancestorStorage,\r
-                    This->rootPropertySetIndex,\r
-                    &curProperty);\r
-\r
-  if (readSuccessful)\r
-  {\r
-    StorageUtl_CopyPropertyToSTATSTG(\r
-      pstatstg,\r
-      &curProperty,\r
-      grfStatFlag);\r
-\r
-    res = S_OK;\r
-    goto end;\r
-  }\r
-\r
-  res = E_FAIL;\r
-\r
-end:\r
-  if (res == S_OK)\r
-  {\r
-    TRACE("<-- STATSTG: pwcsName: %s, type: %ld, cbSize.Low/High: %ld/%ld, grfMode: %08lx, grfLocksSupported: %ld, grfStateBits: %08lx\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);\r
-  }\r
-  TRACE("<-- %08lx\n", res);\r
-  return res;\r
-}\r
-\r
-/************************************************************************\r
- * Storage32BaseImpl_RenameElement (IStorage)\r
- *\r
- * This method will rename the specified element.\r
- *\r
- * See Windows documentation for more details on IStorage methods.\r
- *\r
- * Implementation notes: The method used to rename consists of creating a clone\r
- *    of the deleted StgProperty object setting it with the new name and to\r
- *    perform a DestroyElement of the old StgProperty.\r
- */\r
-HRESULT WINAPI StorageBaseImpl_RenameElement(\r
-            IStorage*        iface,\r
-            const OLECHAR*   pwcsOldName,  /* [in] */\r
-            const OLECHAR*   pwcsNewName)  /* [in] */\r
-{\r
-  StorageBaseImpl *This = (StorageBaseImpl *)iface;\r
-  IEnumSTATSTGImpl* propertyEnumeration;\r
-  StgProperty       currentProperty;\r
-  ULONG             foundPropertyIndex;\r
-\r
-  TRACE("(%p, %s, %s)\n",\r
-       iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));\r
-\r
-  /*\r
-   * Create a property enumeration to search the properties\r
-   */\r
-  propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,\r
-                                                   This->rootPropertySetIndex);\r
-\r
-  /*\r
-   * Search the enumeration for the new property name\r
-   */\r
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,\r
-                                                     pwcsNewName,\r
-                                                     &currentProperty);\r
-\r
-  if (foundPropertyIndex != PROPERTY_NULL)\r
-  {\r
-    /*\r
-     * There is already a property with the new name\r
-     */\r
-    IEnumSTATSTGImpl_Destroy(propertyEnumeration);\r
-    return STG_E_FILEALREADYEXISTS;\r
-  }\r
-\r
-  IEnumSTATSTG_Reset((IEnumSTATSTG*)propertyEnumeration);\r
-\r
-  /*\r
-   * Search the enumeration for the old property name\r
-   */\r
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,\r
-                                                     pwcsOldName,\r
-                                                     &currentProperty);\r
-\r
-  /*\r
-   * Delete the property enumeration since we don't need it anymore\r
-   */\r
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);\r
-\r
-  if (foundPropertyIndex != PROPERTY_NULL)\r
-  {\r
-    StgProperty renamedProperty;\r
-    ULONG       renamedPropertyIndex;\r
-\r
-    /*\r
-     * Setup a new property for the renamed property\r
-     */\r
-    renamedProperty.sizeOfNameString =\r
-      ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);\r
-\r
-    if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)\r
-      return STG_E_INVALIDNAME;\r
-\r
-    strcpyW(renamedProperty.name, pwcsNewName);\r
-\r
-    renamedProperty.propertyType  = currentProperty.propertyType;\r
-    renamedProperty.startingBlock = currentProperty.startingBlock;\r
-    renamedProperty.size.u.LowPart  = currentProperty.size.u.LowPart;\r
-    renamedProperty.size.u.HighPart = currentProperty.size.u.HighPart;\r
-\r
-    renamedProperty.previousProperty = PROPERTY_NULL;\r
-    renamedProperty.nextProperty     = PROPERTY_NULL;\r
-\r
-    /*\r
-     * Bring the dirProperty link in case it is a storage and in which\r
-     * case the renamed storage elements don't require to be reorganized.\r
-     */\r
-    renamedProperty.dirProperty = currentProperty.dirProperty;\r
-\r
-    /* call CoFileTime to get the current time\r
-    renamedProperty.timeStampS1\r
-    renamedProperty.timeStampD1\r
-    renamedProperty.timeStampS2\r
-    renamedProperty.timeStampD2\r
-    renamedProperty.propertyUniqueID\r
-    */\r
-\r
-    /*\r
-     * Obtain a free property in the property chain\r
-     */\r
-    renamedPropertyIndex = getFreeProperty(This->ancestorStorage);\r
-\r
-    /*\r
-     * Save the new property into the new property spot\r
-     */\r
-    StorageImpl_WriteProperty(\r
-      This->ancestorStorage,\r
-      renamedPropertyIndex,\r
-      &renamedProperty);\r
-\r
-    /*\r
-     * Find a spot in the property chain for our newly created property.\r
-     */\r
-    updatePropertyChain(\r
-      (StorageImpl*)This,\r
-      renamedPropertyIndex,\r
-      renamedProperty);\r
-\r
-    /*\r
-     * At this point the renamed property has been inserted in the tree,\r
-     * now, before to Destroy the old property we must zeroed it's dirProperty\r
-     * otherwise the DestroyProperty below will zap it all and we do not want\r
-     * this to happen.\r
-     * Also, we fake that the old property is a storage so the DestroyProperty\r
-     * will not do a SetSize(0) on the stream data.\r
-     *\r
-     * This means that we need to tweek the StgProperty if it is a stream or a\r
-     * non empty storage.\r
-     */\r
-    StorageImpl_ReadProperty(This->ancestorStorage,\r
-                             foundPropertyIndex,\r
-                             &currentProperty);\r
-\r
-    currentProperty.dirProperty  = PROPERTY_NULL;\r
-    currentProperty.propertyType = PROPTYPE_STORAGE;\r
-    StorageImpl_WriteProperty(\r
-      This->ancestorStorage,\r
-      foundPropertyIndex,\r
-      &currentProperty);\r
-\r
-    /*\r
-     * Invoke Destroy to get rid of the ole property and automatically redo\r
-     * the linking of it's previous and next members...\r
-     */\r
-    IStorage_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);\r
-\r
-  }\r
-  else\r
-  {\r
-    /*\r
-     * There is no property with the old name\r
-     */\r
-    return STG_E_FILENOTFOUND;\r
-  }\r
-\r
-  return S_OK;\r
-}\r
-\r
-/************************************************************************\r
- * Storage32BaseImpl_CreateStream (IStorage)\r
- *\r
- * This method will create a stream object within this storage\r
- *\r
- * See Windows documentation for more details on IStorage methods.\r
- */\r
-HRESULT WINAPI StorageBaseImpl_CreateStream(\r
-            IStorage*        iface,\r
-            const OLECHAR*   pwcsName,  /* [string][in] */\r
-            DWORD            grfMode,   /* [in] */\r
-            DWORD            reserved1, /* [in] */\r
-            DWORD            reserved2, /* [in] */\r
-            IStream**        ppstm)     /* [out] */\r
-{\r
-  StorageBaseImpl *This = (StorageBaseImpl *)iface;\r
-  IEnumSTATSTGImpl* propertyEnumeration;\r
-  StgStreamImpl*    newStream;\r
-  StgProperty       currentProperty, newStreamProperty;\r
-  ULONG             foundPropertyIndex, newPropertyIndex;\r
-  DWORD             parent_grfMode;\r
-\r
-  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",\r
-       iface, debugstr_w(pwcsName), grfMode,\r
-       reserved1, reserved2, ppstm);\r
-\r
-  /*\r
-   * Validate parameters\r
-   */\r
-  if (ppstm == 0)\r
-    return STG_E_INVALIDPOINTER;\r
-\r
-  if (pwcsName == 0)\r
-    return STG_E_INVALIDNAME;\r
-\r
-  if (reserved1 || reserved2)\r
-    return STG_E_INVALIDPARAMETER;\r
-\r
-  /*\r
-   * Validate the STGM flags\r
-   */\r
-  if ( FAILED( validateSTGM(grfMode) ))\r
-    return STG_E_INVALIDFLAG;\r
-\r
-  if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) \r
-    return STG_E_INVALIDFLAG;\r
-\r
-  /*\r
-   * As documented.\r
-   */\r
-  if ((grfMode & STGM_DELETEONRELEASE) ||\r
-      (grfMode & STGM_TRANSACTED))\r
-    return STG_E_INVALIDFUNCTION;\r
-\r
-  /*\r
-   * Check that we're compatible with the parent's storage mode\r
-   */\r
-  parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags );\r
-  if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) )\r
-    return STG_E_ACCESSDENIED;\r
-\r
-  /*\r
-   * Initialize the out parameter\r
-   */\r
-  *ppstm = 0;\r
-\r
-  /*\r
-   * Create a property enumeration to search the properties\r
-   */\r
-  propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,\r
-                                                   This->rootPropertySetIndex);\r
-\r
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,\r
-                                                     pwcsName,\r
-                                                     &currentProperty);\r
-\r
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);\r
-\r
-  if (foundPropertyIndex != PROPERTY_NULL)\r
-  {\r
-    /*\r
-     * An element with this name already exists\r
-     */\r
-    if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)\r
-    {\r
-      IStorage_DestroyElement(iface, pwcsName);\r
-    }\r
-    else\r
-      return STG_E_FILEALREADYEXISTS;\r
-  }\r
-\r
-  /*\r
-   * memset the empty property\r
-   */\r
-  memset(&newStreamProperty, 0, sizeof(StgProperty));\r
-\r
-  newStreamProperty.sizeOfNameString =\r
-      ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);\r
-\r
-  if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)\r
-    return STG_E_INVALIDNAME;\r
-\r
-  strcpyW(newStreamProperty.name, pwcsName);\r
-\r
-  newStreamProperty.propertyType  = PROPTYPE_STREAM;\r
-  newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;\r
-  newStreamProperty.size.u.LowPart  = 0;\r
-  newStreamProperty.size.u.HighPart = 0;\r
-\r
-  newStreamProperty.previousProperty = PROPERTY_NULL;\r
-  newStreamProperty.nextProperty     = PROPERTY_NULL;\r
-  newStreamProperty.dirProperty      = PROPERTY_NULL;\r
-\r
-  /* call CoFileTime to get the current time\r
-  newStreamProperty.timeStampS1\r
-  newStreamProperty.timeStampD1\r
-  newStreamProperty.timeStampS2\r
-  newStreamProperty.timeStampD2\r
-  */\r
-\r
-  /*  newStreamProperty.propertyUniqueID */\r
-\r
-  /*\r
-   * Get a free property or create a new one\r
-   */\r
-  newPropertyIndex = getFreeProperty(This->ancestorStorage);\r
-\r
-  /*\r
-   * Save the new property into the new property spot\r
-   */\r
-  StorageImpl_WriteProperty(\r
-    This->ancestorStorage,\r
-    newPropertyIndex,\r
-    &newStreamProperty);\r
-\r
-  /*\r
-   * Find a spot in the property chain for our newly created property.\r
-   */\r
-  updatePropertyChain(\r
-    (StorageImpl*)This,\r
-    newPropertyIndex,\r
-    newStreamProperty);\r
-\r
-  /*\r
-   * Open the stream to return it.\r
-   */\r
-  newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);\r
-\r
-  if (newStream != 0)\r
-  {\r
-    *ppstm = (IStream*)newStream;\r
-\r
-    /*\r
-     * Since we are returning a pointer to the interface, we have to nail down\r
-     * the reference.\r
-     */\r
-    IStream_AddRef(*ppstm);\r
-  }\r
-  else\r
-  {\r
-    return STG_E_INSUFFICIENTMEMORY;\r
-  }\r
-\r
-  return S_OK;\r
-}\r
-\r
-/************************************************************************\r
- * Storage32BaseImpl_SetClass (IStorage)\r
- *\r
- * This method will write the specified CLSID in the property of this\r
- * storage.\r
- *\r
- * See Windows documentation for more details on IStorage methods.\r
- */\r
-HRESULT WINAPI StorageBaseImpl_SetClass(\r
-  IStorage*        iface,\r
-  REFCLSID         clsid) /* [in] */\r
-{\r
-  StorageBaseImpl *This = (StorageBaseImpl *)iface;\r
-  HRESULT hRes = E_FAIL;\r
-  StgProperty curProperty;\r
-  BOOL success;\r
-\r
-  TRACE("(%p, %p)\n", iface, clsid);\r
-\r
-  success = StorageImpl_ReadProperty(This->ancestorStorage,\r
-                                       This->rootPropertySetIndex,\r
-                                       &curProperty);\r
-  if (success)\r
-  {\r
-    curProperty.propertyUniqueID = *clsid;\r
-\r
-    success =  StorageImpl_WriteProperty(This->ancestorStorage,\r
-                                           This->rootPropertySetIndex,\r
-                                           &curProperty);\r
-    if (success)\r
-      hRes = S_OK;\r
-  }\r
-\r
-  return hRes;\r
-}\r
-\r
-/************************************************************************\r
-** Storage32Impl implementation\r
-*/\r
-\r
-/************************************************************************\r
- * Storage32Impl_CreateStorage (IStorage)\r
- *\r
- * This method will create the storage object within the provided storage.\r
- *\r
- * See Windows documentation for more details on IStorage methods.\r
- */\r
-HRESULT WINAPI StorageImpl_CreateStorage(\r
-  IStorage*      iface,\r
-  const OLECHAR  *pwcsName, /* [string][in] */\r
-  DWORD            grfMode,   /* [in] */\r
-  DWORD            reserved1, /* [in] */\r
-  DWORD            reserved2, /* [in] */\r
-  IStorage       **ppstg)   /* [out] */\r
-{\r
-  StorageImpl* const This=(StorageImpl*)iface;\r
-\r
-  IEnumSTATSTGImpl *propertyEnumeration;\r
-  StgProperty      currentProperty;\r
-  StgProperty      newProperty;\r
-  ULONG            foundPropertyIndex;\r
-  ULONG            newPropertyIndex;\r
-  HRESULT          hr;\r
-  DWORD            parent_grfMode;\r
-\r
-  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",\r
-       iface, debugstr_w(pwcsName), grfMode,\r
-       reserved1, reserved2, ppstg);\r
-\r
-  /*\r
-   * Validate parameters\r
-   */\r
-  if (ppstg == 0)\r
-    return STG_E_INVALIDPOINTER;\r
-\r
-  if (pwcsName == 0)\r
-    return STG_E_INVALIDNAME;\r
-\r
-  /*\r
-   * Validate the STGM flags\r
-   */\r
-  if ( FAILED( validateSTGM(grfMode) ) ||\r
-       (grfMode & STGM_DELETEONRELEASE) )\r
-    return STG_E_INVALIDFLAG;\r
-\r
-  /*\r
-   * Check that we're compatible with the parent's storage mode\r
-   */\r
-  parent_grfMode = STGM_ACCESS_MODE( This->base.ancestorStorage->base.openFlags );\r
-  if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) )\r
-    return STG_E_ACCESSDENIED;\r
-\r
-  /*\r
-   * Initialize the out parameter\r
-   */\r
-  *ppstg = 0;\r
-\r
-  /*\r
-   * Create a property enumeration and search the properties\r
-   */\r
-  propertyEnumeration = IEnumSTATSTGImpl_Construct( This->base.ancestorStorage,\r
-                                                    This->base.rootPropertySetIndex);\r
-\r
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,\r
-                                                     pwcsName,\r
-                                                     &currentProperty);\r
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);\r
-\r
-  if (foundPropertyIndex != PROPERTY_NULL)\r
-  {\r
-    /*\r
-     * An element with this name already exists\r
-     */\r
-    if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)\r
-      IStorage_DestroyElement(iface, pwcsName);\r
-    else\r
-      return STG_E_FILEALREADYEXISTS;\r
-  }\r
-\r
-  /*\r
-   * memset the empty property\r
-   */\r
-  memset(&newProperty, 0, sizeof(StgProperty));\r
-\r
-  newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);\r
-\r
-  if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)\r
-    return STG_E_INVALIDNAME;\r
-\r
-  strcpyW(newProperty.name, pwcsName);\r
-\r
-  newProperty.propertyType  = PROPTYPE_STORAGE;\r
-  newProperty.startingBlock = BLOCK_END_OF_CHAIN;\r
-  newProperty.size.u.LowPart  = 0;\r
-  newProperty.size.u.HighPart = 0;\r
-\r
-  newProperty.previousProperty = PROPERTY_NULL;\r
-  newProperty.nextProperty     = PROPERTY_NULL;\r
-  newProperty.dirProperty      = PROPERTY_NULL;\r
-\r
-  /* call CoFileTime to get the current time\r
-  newProperty.timeStampS1\r
-  newProperty.timeStampD1\r
-  newProperty.timeStampS2\r
-  newProperty.timeStampD2\r
-  */\r
-\r
-  /*  newStorageProperty.propertyUniqueID */\r
-\r
-  /*\r
-   * Obtain a free property in the property chain\r
-   */\r
-  newPropertyIndex = getFreeProperty(This->base.ancestorStorage);\r
-\r
-  /*\r
-   * Save the new property into the new property spot\r
-   */\r
-  StorageImpl_WriteProperty(\r
-    This->base.ancestorStorage,\r
-    newPropertyIndex,\r
-    &newProperty);\r
-\r
-  /*\r
-   * Find a spot in the property chain for our newly created property.\r
-   */\r
-  updatePropertyChain(\r
-    This,\r
-    newPropertyIndex,\r
-    newProperty);\r
-\r
-  /*\r
-   * Open it to get a pointer to return.\r
-   */\r
-  hr = IStorage_OpenStorage(\r
-         iface,\r
-         (const OLECHAR*)pwcsName,\r
-         0,\r
-         grfMode,\r
-         0,\r
-         0,\r
-         ppstg);\r
-\r
-  if( (hr != S_OK) || (*ppstg == NULL))\r
-  {\r
-    return hr;\r
-  }\r
-\r
-\r
-  return S_OK;\r
-}\r
-\r
-\r
-/***************************************************************************\r
- *\r
- * Internal Method\r
- *\r
- * Get a free property or create a new one.\r
- */\r
-static ULONG getFreeProperty(\r
-  StorageImpl *storage)\r
-{\r
-  ULONG       currentPropertyIndex = 0;\r
-  ULONG       newPropertyIndex     = PROPERTY_NULL;\r
-  BOOL      readSuccessful        = TRUE;\r
-  StgProperty currentProperty;\r
-\r
-  do\r
-  {\r
-    /*\r
-     * Start by reading the root property\r
-     */\r
-    readSuccessful = StorageImpl_ReadProperty(storage->base.ancestorStorage,\r
-                                               currentPropertyIndex,\r
-                                               &currentProperty);\r
-    if (readSuccessful)\r
-    {\r
-      if (currentProperty.sizeOfNameString == 0)\r
-      {\r
-        /*\r
-         * The property existis and is available, we found it.\r
-         */\r
-        newPropertyIndex = currentPropertyIndex;\r
-      }\r
-    }\r
-    else\r
-    {\r
-      /*\r
-       * We exhausted the property list, we will create more space below\r
-       */\r
-      newPropertyIndex = currentPropertyIndex;\r
-    }\r
-    currentPropertyIndex++;\r
-\r
-  } while (newPropertyIndex == PROPERTY_NULL);\r
-\r
-  /*\r
-   * grow the property chain\r
-   */\r
-  if (! readSuccessful)\r
-  {\r
-    StgProperty    emptyProperty;\r
-    ULARGE_INTEGER newSize;\r
-    ULONG          propertyIndex;\r
-    ULONG          lastProperty  = 0;\r
-    ULONG          blockCount    = 0;\r
-\r
-    /*\r
-     * obtain the new count of property blocks\r
-     */\r
-    blockCount = BlockChainStream_GetCount(\r
-                   storage->base.ancestorStorage->rootBlockChain)+1;\r
-\r
-    /*\r
-     * initialize the size used by the property stream\r
-     */\r
-    newSize.u.HighPart = 0;\r
-    newSize.u.LowPart  = storage->bigBlockSize * blockCount;\r
-\r
-    /*\r
-     * add a property block to the property chain\r
-     */\r
-    BlockChainStream_SetSize(storage->base.ancestorStorage->rootBlockChain, newSize);\r
-\r
-    /*\r
-     * memset the empty property in order to initialize the unused newly\r
-     * created property\r
-     */\r
-    memset(&emptyProperty, 0, sizeof(StgProperty));\r
-\r
-    /*\r
-     * initialize them\r
-     */\r
-    lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;\r
-\r
-    for(\r
-      propertyIndex = newPropertyIndex;\r
-      propertyIndex < lastProperty;\r
-      propertyIndex++)\r
-    {\r
-      StorageImpl_WriteProperty(\r
-        storage->base.ancestorStorage,\r
-        propertyIndex,\r
-        &emptyProperty);\r
-    }\r
-  }\r
-\r
-  return newPropertyIndex;\r
-}\r
-\r
-/****************************************************************************\r
- *\r
- * Internal Method\r
- *\r
- * Case insensitive comparaison of StgProperty.name by first considering\r
- * their size.\r
- *\r
- * Returns <0 when newPrpoerty < currentProperty\r
- *         >0 when newPrpoerty > currentProperty\r
- *          0 when newPrpoerty == currentProperty\r
- */\r
-static LONG propertyNameCmp(\r
-    const OLECHAR *newProperty,\r
-    const OLECHAR *currentProperty)\r
-{\r
-  LONG diff      = lstrlenW(newProperty) - lstrlenW(currentProperty);\r
-\r
-  if (diff == 0)\r
-  {\r
-    /*\r
-     * We compare the string themselves only when they are of the same length\r
-     */\r
-    diff = lstrcmpiW( newProperty, currentProperty);\r
-  }\r
-\r
-  return diff;\r
-}\r
-\r
-/****************************************************************************\r
- *\r
- * Internal Method\r
- *\r
- * Properly link this new element in the property chain.\r
- */\r
-static void updatePropertyChain(\r
-  StorageImpl *storage,\r
-  ULONG         newPropertyIndex,\r
-  StgProperty   newProperty)\r
-{\r
-  StgProperty currentProperty;\r
-\r
-  /*\r
-   * Read the root property\r
-   */\r
-  StorageImpl_ReadProperty(storage->base.ancestorStorage,\r
-                             storage->base.rootPropertySetIndex,\r
-                             &currentProperty);\r
-\r
-  if (currentProperty.dirProperty != PROPERTY_NULL)\r
-  {\r
-    /*\r
-     * The root storage contains some element, therefore, start the research\r
-     * for the appropriate location.\r
-     */\r
-    BOOL found = 0;\r
-    ULONG  current, next, previous, currentPropertyId;\r
-\r
-    /*\r
-     * Keep the StgProperty sequence number of the storage first property\r
-     */\r
-    currentPropertyId = currentProperty.dirProperty;\r
-\r
-    /*\r
-     * Read\r
-     */\r
-    StorageImpl_ReadProperty(storage->base.ancestorStorage,\r
-                               currentProperty.dirProperty,\r
-                               &currentProperty);\r
-\r
-    previous = currentProperty.previousProperty;\r
-    next     = currentProperty.nextProperty;\r
-    current  = currentPropertyId;\r
-\r
-    while (found == 0)\r
-    {\r
-      LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);\r
-\r
-      if (diff < 0)\r
-      {\r
-        if (previous != PROPERTY_NULL)\r
-        {\r
-          StorageImpl_ReadProperty(storage->base.ancestorStorage,\r
-                                     previous,\r
-                                     &currentProperty);\r
-          current = previous;\r
-        }\r
-        else\r
-        {\r
-          currentProperty.previousProperty = newPropertyIndex;\r
-          StorageImpl_WriteProperty(storage->base.ancestorStorage,\r
-                                      current,\r
-                                      &currentProperty);\r
-          found = 1;\r
-        }\r
-      }\r
-      else if (diff > 0)\r
-      {\r
-        if (next != PROPERTY_NULL)\r
-        {\r
-          StorageImpl_ReadProperty(storage->base.ancestorStorage,\r
-                                     next,\r
-                                     &currentProperty);\r
-          current = next;\r
-        }\r
-        else\r
-        {\r
-          currentProperty.nextProperty = newPropertyIndex;\r
-          StorageImpl_WriteProperty(storage->base.ancestorStorage,\r
-                                      current,\r
-                                      &currentProperty);\r
-          found = 1;\r
-        }\r
-      }\r
-      else\r
-      {\r
-       /*\r
-        * Trying to insert an item with the same name in the\r
-        * subtree structure.\r
-        */\r
-       assert(FALSE);\r
-      }\r
-\r
-      previous = currentProperty.previousProperty;\r
-      next     = currentProperty.nextProperty;\r
-    }\r
-  }\r
-  else\r
-  {\r
-    /*\r
-     * The root storage is empty, link the new property to it's dir property\r
-     */\r
-    currentProperty.dirProperty = newPropertyIndex;\r
-    StorageImpl_WriteProperty(storage->base.ancestorStorage,\r
-                                storage->base.rootPropertySetIndex,\r
-                                &currentProperty);\r
-  }\r
-}\r
-\r
-\r
-/*************************************************************************\r
- * CopyTo (IStorage)\r
- */\r
-HRESULT WINAPI StorageImpl_CopyTo(\r
-  IStorage*   iface,\r
-  DWORD       ciidExclude,  /* [in] */\r
-  const IID*  rgiidExclude, /* [size_is][unique][in] */\r
-  SNB         snbExclude,   /* [unique][in] */\r
-  IStorage*   pstgDest)     /* [unique][in] */\r
-{\r
-  IEnumSTATSTG *elements     = 0;\r
-  STATSTG      curElement, strStat;\r
-  HRESULT      hr;\r
-  IStorage     *pstgTmp, *pstgChild;\r
-  IStream      *pstrTmp, *pstrChild;\r
-\r
-  if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))\r
-    FIXME("Exclude option not implemented\n");\r
-\r
-  TRACE("(%p, %ld, %p, %p, %p)\n",\r
-       iface, ciidExclude, rgiidExclude,\r
-       snbExclude, pstgDest);\r
-\r
-  /*\r
-   * Perform a sanity check\r
-   */\r
-  if ( pstgDest == 0 )\r
-    return STG_E_INVALIDPOINTER;\r
-\r
-  /*\r
-   * Enumerate the elements\r
-   */\r
-  hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );\r
-\r
-  if ( hr != S_OK )\r
-    return hr;\r
-\r
-  /*\r
-   * set the class ID\r
-   */\r
-  IStorage_Stat( iface, &curElement, STATFLAG_NONAME);\r
-  IStorage_SetClass( pstgDest, &curElement.clsid );\r
-\r
-  do\r
-  {\r
-    /*\r
-     * Obtain the next element\r
-     */\r
-    hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );\r
-\r
-    if ( hr == S_FALSE )\r
-    {\r
-      hr = S_OK;   /* done, every element has been copied */\r
-      break;\r
-    }\r
-\r
-    if (curElement.type == STGTY_STORAGE)\r
-    {\r
-      /*\r
-       * open child source storage\r
-       */\r
-      hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,\r
-                                STGM_READ|STGM_SHARE_EXCLUSIVE,\r
-                                NULL, 0, &pstgChild );\r
-\r
-      if (hr != S_OK)\r
-        break;\r
-\r
-      /*\r
-       * Check if destination storage is not a child of the source\r
-       * storage, which will cause an infinite loop\r
-       */\r
-      if (pstgChild == pstgDest)\r
-      {\r
-       IEnumSTATSTG_Release(elements);\r
-\r
-       return STG_E_ACCESSDENIED;\r
-      }\r
-\r
-      /*\r
-       * create a new storage in destination storage\r
-       */\r
-      hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,\r
-                                   STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,\r
-                                  0, 0,\r
-                                   &pstgTmp );\r
-      /*\r
-       * if it already exist, don't create a new one use this one\r
-       */\r
-      if (hr == STG_E_FILEALREADYEXISTS)\r
-      {\r
-        hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,\r
-                                   STGM_WRITE|STGM_SHARE_EXCLUSIVE,\r
-                                   NULL, 0, &pstgTmp );\r
-      }\r
-\r
-      if (hr != S_OK)\r
-        break;\r
-\r
-\r
-      /*\r
-       * do the copy recursively\r
-       */\r
-      hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,\r
-                               snbExclude, pstgTmp );\r
-\r
-      IStorage_Release( pstgTmp );\r
-      IStorage_Release( pstgChild );\r
-    }\r
-    else if (curElement.type == STGTY_STREAM)\r
-    {\r
-      /*\r
-       * create a new stream in destination storage. If the stream already\r
-       * exist, it will be deleted and a new one will be created.\r
-       */\r
-      hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,\r
-                                  STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,\r
-                                  0, 0, &pstrTmp );\r
-\r
-      if (hr != S_OK)\r
-        break;\r
-\r
-      /*\r
-       * open child stream storage\r
-       */\r
-      hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,\r
-                               STGM_READ|STGM_SHARE_EXCLUSIVE,\r
-                               0, &pstrChild );\r
-\r
-      if (hr != S_OK)\r
-        break;\r
-\r
-      /*\r
-       * Get the size of the source stream\r
-       */\r
-      IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );\r
-\r
-      /*\r
-       * Set the size of the destination stream.\r
-       */\r
-      IStream_SetSize(pstrTmp, strStat.cbSize);\r
-\r
-      /*\r
-       * do the copy\r
-       */\r
-      hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,\r
-                           NULL, NULL );\r
-\r
-      IStream_Release( pstrTmp );\r
-      IStream_Release( pstrChild );\r
-    }\r
-    else\r
-    {\r
-      WARN("unknown element type: %ld\n", curElement.type);\r
-    }\r
-\r
-  } while (hr == S_OK);\r
-\r
-  /*\r
-   * Clean-up\r
-   */\r
-  IEnumSTATSTG_Release(elements);\r
-\r
-  return hr;\r
-}\r
-\r
-/*************************************************************************\r
- * MoveElementTo (IStorage)\r
- */\r
-HRESULT WINAPI StorageImpl_MoveElementTo(\r
-  IStorage*     iface,\r
-  const OLECHAR *pwcsName,   /* [string][in] */\r
-  IStorage      *pstgDest,   /* [unique][in] */\r
-  const OLECHAR *pwcsNewName,/* [string][in] */\r
-  DWORD           grfFlags)    /* [in] */\r
-{\r
-  FIXME("not implemented!\n");\r
-  return E_NOTIMPL;\r
-}\r
-\r
-/*************************************************************************\r
- * Commit (IStorage)\r
- */\r
-HRESULT WINAPI StorageImpl_Commit(\r
-  IStorage*   iface,\r
-  DWORD         grfCommitFlags)/* [in] */\r
-{\r
-  FIXME("(%ld): stub!\n", grfCommitFlags);\r
-  return S_OK;\r
-}\r
-\r
-/*************************************************************************\r
- * Revert (IStorage)\r
- */\r
-HRESULT WINAPI StorageImpl_Revert(\r
-  IStorage* iface)\r
-{\r
-  FIXME("not implemented!\n");\r
-  return E_NOTIMPL;\r
-}\r
-\r
-/*************************************************************************\r
- * DestroyElement (IStorage)\r
- *\r
- * Stategy: This implementation is build this way for simplicity not for speed.\r
- *          I always delete the top most element of the enumeration and adjust\r
- *          the deleted element pointer all the time.  This takes longer to\r
- *          do but allow to reinvoke DestroyElement whenever we encounter a\r
- *          storage object.  The optimisation reside in the usage of another\r
- *          enumeration stategy that would give all the leaves of a storage\r
- *          first. (postfix order)\r
- */\r
-HRESULT WINAPI StorageImpl_DestroyElement(\r
-  IStorage*     iface,\r
-  const OLECHAR *pwcsName)/* [string][in] */\r
-{\r
-  StorageImpl* const This=(StorageImpl*)iface;\r
-\r
-  IEnumSTATSTGImpl* propertyEnumeration;\r
-  HRESULT           hr = S_OK;\r
-  BOOL            res;\r
-  StgProperty       propertyToDelete;\r
-  StgProperty       parentProperty;\r
-  ULONG             foundPropertyIndexToDelete;\r
-  ULONG             typeOfRelation;\r
-  ULONG             parentPropertyId;\r
-\r
-  TRACE("(%p, %s)\n",\r
-       iface, debugstr_w(pwcsName));\r
-\r
-  /*\r
-   * Perform a sanity check on the parameters.\r
-   */\r
-  if (pwcsName==NULL)\r
-    return STG_E_INVALIDPOINTER;\r
-\r
-  /*\r
-   * Create a property enumeration to search the property with the given name\r
-   */\r
-  propertyEnumeration = IEnumSTATSTGImpl_Construct(\r
-    This->base.ancestorStorage,\r
-    This->base.rootPropertySetIndex);\r
-\r
-  foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(\r
-    propertyEnumeration,\r
-    pwcsName,\r
-    &propertyToDelete);\r
-\r
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);\r
-\r
-  if ( foundPropertyIndexToDelete == PROPERTY_NULL )\r
-  {\r
-    return STG_E_FILENOTFOUND;\r
-  }\r
-\r
-  /*\r
-   * Find the parent property of the property to delete (the one that\r
-   * link to it).  If This->dirProperty == foundPropertyIndexToDelete,\r
-   * the parent is This. Otherwise, the parent is one of it's sibling...\r
-   */\r
-\r
-  /*\r
-   * First, read This's StgProperty..\r
-   */\r
-  res = StorageImpl_ReadProperty(\r
-          This->base.ancestorStorage,\r
-          This->base.rootPropertySetIndex,\r
-          &parentProperty);\r
-\r
-  assert(res);\r
-\r
-  /*\r
-   * Second, check to see if by any chance the actual storage (This) is not\r
-   * the parent of the property to delete... We never know...\r
-   */\r
-  if ( parentProperty.dirProperty == foundPropertyIndexToDelete )\r
-  {\r
-    /*\r
-     * Set data as it would have been done in the else part...\r
-     */\r
-    typeOfRelation   = PROPERTY_RELATION_DIR;\r
-    parentPropertyId = This->base.rootPropertySetIndex;\r
-  }\r
-  else\r
-  {\r
-    /*\r
-     * Create a property enumeration to search the parent properties, and\r
-     * delete it once done.\r
-     */\r
-    IEnumSTATSTGImpl* propertyEnumeration2;\r
-\r
-    propertyEnumeration2 = IEnumSTATSTGImpl_Construct(\r
-      This->base.ancestorStorage,\r
-      This->base.rootPropertySetIndex);\r
-\r
-    typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(\r
-      propertyEnumeration2,\r
-      foundPropertyIndexToDelete,\r
-      &parentProperty,\r
-      &parentPropertyId);\r
-\r
-    IEnumSTATSTGImpl_Destroy(propertyEnumeration2);\r
-  }\r
-\r
-  if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )\r
-  {\r
-    hr = deleteStorageProperty(\r
-           This,\r
-           foundPropertyIndexToDelete,\r
-           propertyToDelete);\r
-  }\r
-  else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )\r
-  {\r
-    hr = deleteStreamProperty(\r
-           This,\r
-           foundPropertyIndexToDelete,\r
-           propertyToDelete);\r
-  }\r
-\r
-  if (hr!=S_OK)\r
-    return hr;\r
-\r
-  /*\r
-   * Adjust the property chain\r
-   */\r
-  hr = adjustPropertyChain(\r
-        This,\r
-        propertyToDelete,\r
-        parentProperty,\r
-        parentPropertyId,\r
-        typeOfRelation);\r
-\r
-  return hr;\r
-}\r
-\r
-\r
-/************************************************************************\r
- * StorageImpl_Stat (IStorage)\r
- *\r
- * This method will retrieve information about this storage object.\r
- *\r
- * See Windows documentation for more details on IStorage methods.\r
- */\r
-HRESULT WINAPI StorageImpl_Stat( IStorage* iface,\r
-                                 STATSTG*  pstatstg,     /* [out] */\r
-                                 DWORD     grfStatFlag)  /* [in] */\r
-{\r
-  StorageImpl* const This = (StorageImpl*)iface;\r
-  HRESULT result = StorageBaseImpl_Stat( iface, pstatstg, grfStatFlag );\r
-\r
-  if ( !FAILED(result) && ((grfStatFlag & STATFLAG_NONAME) == 0) && This->pwcsName )\r
-  {\r
-      CoTaskMemFree(pstatstg->pwcsName);\r
-      pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));\r
-      strcpyW(pstatstg->pwcsName, This->pwcsName);\r
-  }\r
-\r
-  return result;\r
-}\r
-\r
-\r
-\r
-/*********************************************************************\r
- *\r
- * Internal Method\r
- *\r
- * Perform the deletion of a complete storage node\r
- *\r
- */\r
-static HRESULT deleteStorageProperty(\r
-  StorageImpl *parentStorage,\r
-  ULONG        indexOfPropertyToDelete,\r
-  StgProperty  propertyToDelete)\r
-{\r
-  IEnumSTATSTG *elements     = 0;\r
-  IStorage   *childStorage = 0;\r
-  STATSTG      currentElement;\r
-  HRESULT      hr;\r
-  HRESULT      destroyHr = S_OK;\r
-\r
-  /*\r
-   * Open the storage and enumerate it\r
-   */\r
-  hr = StorageBaseImpl_OpenStorage(\r
-        (IStorage*)parentStorage,\r
-        propertyToDelete.name,\r
-        0,\r
-        STGM_SHARE_EXCLUSIVE,\r
-        0,\r
-        0,\r
-        &childStorage);\r
-\r
-  if (hr != S_OK)\r
-  {\r
-    return hr;\r
-  }\r
-\r
-  /*\r
-   * Enumerate the elements\r
-   */\r
-  IStorage_EnumElements( childStorage, 0, 0, 0, &elements);\r
-\r
-  do\r
-  {\r
-    /*\r
-     * Obtain the next element\r
-     */\r
-    hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);\r
-    if (hr==S_OK)\r
-    {\r
-      destroyHr = StorageImpl_DestroyElement(\r
-                    (IStorage*)childStorage,\r
-                    (OLECHAR*)currentElement.pwcsName);\r
-\r
-      CoTaskMemFree(currentElement.pwcsName);\r
-    }\r
-\r
-    /*\r
-     * We need to Reset the enumeration every time because we delete elements\r
-     * and the enumeration could be invalid\r
-     */\r
-    IEnumSTATSTG_Reset(elements);\r
-\r
-  } while ((hr == S_OK) && (destroyHr == S_OK));\r
-\r
-  /*\r
-   * Invalidate the property by zeroing it's name member.\r
-   */\r
-  propertyToDelete.sizeOfNameString = 0;\r
-\r
-  StorageImpl_WriteProperty(parentStorage->base.ancestorStorage,\r
-                            indexOfPropertyToDelete,\r
-                            &propertyToDelete);\r
-\r
-  IStorage_Release(childStorage);\r
-  IEnumSTATSTG_Release(elements);\r
-\r
-  return destroyHr;\r
-}\r
-\r
-/*********************************************************************\r
- *\r
- * Internal Method\r
- *\r
- * Perform the deletion of a stream node\r
- *\r
- */\r
-static HRESULT deleteStreamProperty(\r
-  StorageImpl *parentStorage,\r
-  ULONG         indexOfPropertyToDelete,\r
-  StgProperty   propertyToDelete)\r
-{\r
-  IStream      *pis;\r
-  HRESULT        hr;\r
-  ULARGE_INTEGER size;\r
-\r
-  size.u.HighPart = 0;\r
-  size.u.LowPart = 0;\r
-\r
-  hr = StorageBaseImpl_OpenStream(\r
-         (IStorage*)parentStorage,\r
-         (OLECHAR*)propertyToDelete.name,\r
-         NULL,\r
-         STGM_WRITE | STGM_SHARE_EXCLUSIVE,\r
-         0,\r
-         &pis);\r
-\r
-  if (hr!=S_OK)\r
-  {\r
-    return(hr);\r
-  }\r
-\r
-  /*\r
-   * Zap the stream\r
-   */\r
-  hr = IStream_SetSize(pis, size);\r
-\r
-  if(hr != S_OK)\r
-  {\r
-    return hr;\r
-  }\r
-\r
-  /*\r
-   * Release the stream object.\r
-   */\r
-  IStream_Release(pis);\r
-\r
-  /*\r
-   * Invalidate the property by zeroing it's name member.\r
-   */\r
-  propertyToDelete.sizeOfNameString = 0;\r
-\r
-  /*\r
-   * Here we should re-read the property so we get the updated pointer\r
-   * but since we are here to zap it, I don't do it...\r
-   */\r
-  StorageImpl_WriteProperty(\r
-    parentStorage->base.ancestorStorage,\r
-    indexOfPropertyToDelete,\r
-    &propertyToDelete);\r
-\r
-  return S_OK;\r
-}\r
-\r
-/*********************************************************************\r
- *\r
- * Internal Method\r
- *\r
- * Finds a placeholder for the StgProperty within the Storage\r
- *\r
- */\r
-static HRESULT findPlaceholder(\r
-  StorageImpl *storage,\r
-  ULONG         propertyIndexToStore,\r
-  ULONG         storePropertyIndex,\r
-  INT         typeOfRelation)\r
-{\r
-  StgProperty storeProperty;\r
-  HRESULT     hr = S_OK;\r
-  BOOL      res = TRUE;\r
-\r
-  /*\r
-   * Read the storage property\r
-   */\r
-  res = StorageImpl_ReadProperty(\r
-          storage->base.ancestorStorage,\r
-          storePropertyIndex,\r
-          &storeProperty);\r
-\r
-  if(! res)\r
-  {\r
-    return E_FAIL;\r
-  }\r
-\r
-  if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)\r
-  {\r
-    if (storeProperty.previousProperty != PROPERTY_NULL)\r
-    {\r
-      return findPlaceholder(\r
-               storage,\r
-               propertyIndexToStore,\r
-               storeProperty.previousProperty,\r
-               typeOfRelation);\r
-    }\r
-    else\r
-    {\r
-      storeProperty.previousProperty = propertyIndexToStore;\r
-    }\r
-  }\r
-  else if (typeOfRelation == PROPERTY_RELATION_NEXT)\r
-  {\r
-    if (storeProperty.nextProperty != PROPERTY_NULL)\r
-    {\r
-      return findPlaceholder(\r
-               storage,\r
-               propertyIndexToStore,\r
-               storeProperty.nextProperty,\r
-               typeOfRelation);\r
-    }\r
-    else\r
-    {\r
-      storeProperty.nextProperty = propertyIndexToStore;\r
-    }\r
-  }\r
-  else if (typeOfRelation == PROPERTY_RELATION_DIR)\r
-  {\r
-    if (storeProperty.dirProperty != PROPERTY_NULL)\r
-    {\r
-      return findPlaceholder(\r
-               storage,\r
-               propertyIndexToStore,\r
-               storeProperty.dirProperty,\r
-               typeOfRelation);\r
-    }\r
-    else\r
-    {\r
-      storeProperty.dirProperty = propertyIndexToStore;\r
-    }\r
-  }\r
-\r
-  hr = StorageImpl_WriteProperty(\r
-         storage->base.ancestorStorage,\r
-         storePropertyIndex,\r
-         &storeProperty);\r
-\r
-  if(! hr)\r
-  {\r
-    return E_FAIL;\r
-  }\r
-\r
-  return S_OK;\r
-}\r
-\r
-/*************************************************************************\r
- *\r
- * Internal Method\r
- *\r
- * This method takes the previous and the next property link of a property\r
- * to be deleted and find them a place in the Storage.\r
- */\r
-static HRESULT adjustPropertyChain(\r
-  StorageImpl *This,\r
-  StgProperty   propertyToDelete,\r
-  StgProperty   parentProperty,\r
-  ULONG         parentPropertyId,\r
-  INT         typeOfRelation)\r
-{\r
-  ULONG   newLinkProperty        = PROPERTY_NULL;\r
-  BOOL  needToFindAPlaceholder = FALSE;\r
-  ULONG   storeNode              = PROPERTY_NULL;\r
-  ULONG   toStoreNode            = PROPERTY_NULL;\r
-  INT   relationType           = 0;\r
-  HRESULT hr                     = S_OK;\r
-  BOOL  res                    = TRUE;\r
-\r
-  if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)\r
-  {\r
-    if (propertyToDelete.previousProperty != PROPERTY_NULL)\r
-    {\r
-      /*\r
-       * Set the parent previous to the property to delete previous\r
-       */\r
-      newLinkProperty = propertyToDelete.previousProperty;\r
-\r
-      if (propertyToDelete.nextProperty != PROPERTY_NULL)\r
-      {\r
-        /*\r
-         * We also need to find a storage for the other link, setup variables\r
-         * to do this at the end...\r
-         */\r
-        needToFindAPlaceholder = TRUE;\r
-        storeNode              = propertyToDelete.previousProperty;\r
-        toStoreNode            = propertyToDelete.nextProperty;\r
-        relationType           = PROPERTY_RELATION_NEXT;\r
-      }\r
-    }\r
-    else if (propertyToDelete.nextProperty != PROPERTY_NULL)\r
-    {\r
-      /*\r
-       * Set the parent previous to the property to delete next\r
-       */\r
-      newLinkProperty = propertyToDelete.nextProperty;\r
-    }\r
-\r
-    /*\r
-     * Link it for real...\r
-     */\r
-    parentProperty.previousProperty = newLinkProperty;\r
-\r
-  }\r
-  else if (typeOfRelation == PROPERTY_RELATION_NEXT)\r
-  {\r
-    if (propertyToDelete.previousProperty != PROPERTY_NULL)\r
-    {\r
-      /*\r
-       * Set the parent next to the property to delete next previous\r
-       */\r
-      newLinkProperty = propertyToDelete.previousProperty;\r
-\r
-      if (propertyToDelete.nextProperty != PROPERTY_NULL)\r
-      {\r
-        /*\r
-         * We also need to find a storage for the other link, setup variables\r
-         * to do this at the end...\r
-         */\r
-        needToFindAPlaceholder = TRUE;\r
-        storeNode              = propertyToDelete.previousProperty;\r
-        toStoreNode            = propertyToDelete.nextProperty;\r
-        relationType           = PROPERTY_RELATION_NEXT;\r
-      }\r
-    }\r
-    else if (propertyToDelete.nextProperty != PROPERTY_NULL)\r
-    {\r
-      /*\r
-       * Set the parent next to the property to delete next\r
-       */\r
-      newLinkProperty = propertyToDelete.nextProperty;\r
-    }\r
-\r
-    /*\r
-     * Link it for real...\r
-     */\r
-    parentProperty.nextProperty = newLinkProperty;\r
-  }\r
-  else /* (typeOfRelation == PROPERTY_RELATION_DIR) */\r
-  {\r
-    if (propertyToDelete.previousProperty != PROPERTY_NULL)\r
-    {\r
-      /*\r
-       * Set the parent dir to the property to delete previous\r
-       */\r
-      newLinkProperty = propertyToDelete.previousProperty;\r
-\r
-      if (propertyToDelete.nextProperty != PROPERTY_NULL)\r
-      {\r
-        /*\r
-         * We also need to find a storage for the other link, setup variables\r
-         * to do this at the end...\r
-         */\r
-        needToFindAPlaceholder = TRUE;\r
-        storeNode              = propertyToDelete.previousProperty;\r
-        toStoreNode            = propertyToDelete.nextProperty;\r
-        relationType           = PROPERTY_RELATION_NEXT;\r
-      }\r
-    }\r
-    else if (propertyToDelete.nextProperty != PROPERTY_NULL)\r
-    {\r
-      /*\r
-       * Set the parent dir to the property to delete next\r
-       */\r
-      newLinkProperty = propertyToDelete.nextProperty;\r
-    }\r
-\r
-    /*\r
-     * Link it for real...\r
-     */\r
-    parentProperty.dirProperty = newLinkProperty;\r
-  }\r
-\r
-  /*\r
-   * Write back the parent property\r
-   */\r
-  res = StorageImpl_WriteProperty(\r
-          This->base.ancestorStorage,\r
-          parentPropertyId,\r
-          &parentProperty);\r
-  if(! res)\r
-  {\r
-    return E_FAIL;\r
-  }\r
-\r
-  /*\r
-   * If a placeholder is required for the other link, then, find one and\r
-   * get out of here...\r
-   */\r
-  if (needToFindAPlaceholder)\r
-  {\r
-    hr = findPlaceholder(\r
-           This,\r
-           toStoreNode,\r
-           storeNode,\r
-           relationType);\r
-  }\r
-\r
-  return hr;\r
-}\r
-\r
-\r
-/******************************************************************************\r
- * SetElementTimes (IStorage)\r
- */\r
-HRESULT WINAPI StorageImpl_SetElementTimes(\r
-  IStorage*     iface,\r
-  const OLECHAR *pwcsName,/* [string][in] */\r
-  const FILETIME  *pctime,  /* [in] */\r
-  const FILETIME  *patime,  /* [in] */\r
-  const FILETIME  *pmtime)  /* [in] */\r
-{\r
-  FIXME("(%s,...), stub!\n",debugstr_w(pwcsName));\r
-  return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- * SetStateBits (IStorage)\r
- */\r
-HRESULT WINAPI StorageImpl_SetStateBits(\r
-  IStorage*   iface,\r
-  DWORD         grfStateBits,/* [in] */\r
-  DWORD         grfMask)     /* [in] */\r
-{\r
-  FIXME("not implemented!\n");\r
-  return E_NOTIMPL;\r
-}\r
-\r
-/*\r
- * Virtual function table for the IStorage32Impl class.\r
- */\r
-static IStorageVtbl Storage32Impl_Vtbl =\r
-{\r
-    StorageBaseImpl_QueryInterface,\r
-    StorageBaseImpl_AddRef,\r
-    StorageBaseImpl_Release,\r
-    StorageBaseImpl_CreateStream,\r
-    StorageBaseImpl_OpenStream,\r
-    StorageImpl_CreateStorage,\r
-    StorageBaseImpl_OpenStorage,\r
-    StorageImpl_CopyTo,\r
-    StorageImpl_MoveElementTo,\r
-    StorageImpl_Commit,\r
-    StorageImpl_Revert,\r
-    StorageBaseImpl_EnumElements,\r
-    StorageImpl_DestroyElement,\r
-    StorageBaseImpl_RenameElement,\r
-    StorageImpl_SetElementTimes,\r
-    StorageBaseImpl_SetClass,\r
-    StorageImpl_SetStateBits,\r
-    StorageImpl_Stat\r
-};\r
-\r
-HRESULT StorageImpl_Construct(\r
-  StorageImpl* This,\r
-  HANDLE       hFile,\r
-  LPCOLESTR    pwcsName,\r
-  ILockBytes*  pLkbyt,\r
-  DWORD        openFlags,\r
-  BOOL         fileBased,\r
-  BOOL         fileCreate)\r
-{\r
-  HRESULT     hr = S_OK;\r
-  StgProperty currentProperty;\r
-  BOOL      readSuccessful;\r
-  ULONG       currentPropertyIndex;\r
-\r
-  if ( FAILED( validateSTGM(openFlags) ))\r
-    return STG_E_INVALIDFLAG;\r
-\r
-  memset(This, 0, sizeof(StorageImpl));\r
-\r
-  /*\r
-   * Initialize the virtual function table.\r
-   */\r
-  This->base.lpVtbl = &Storage32Impl_Vtbl;\r
-  This->base.pssVtbl = &IPropertySetStorage_Vtbl;\r
-  This->base.v_destructor = &StorageImpl_Destroy;\r
-  This->base.openFlags = openFlags;\r
-\r
-  /*\r
-   * This is the top-level storage so initialize the ancestor pointer\r
-   * to this.\r
-   */\r
-  This->base.ancestorStorage = This;\r
-\r
-  /*\r
-   * Initialize the physical support of the storage.\r
-   */\r
-  This->hFile = hFile;\r
-\r
-  /*\r
-   * Store copy of file path.\r
-   */\r
-  if(pwcsName) {\r
-      This->pwcsName = HeapAlloc(GetProcessHeap(), 0,\r
-                                (lstrlenW(pwcsName)+1)*sizeof(WCHAR));\r
-      if (!This->pwcsName)\r
-         return STG_E_INSUFFICIENTMEMORY;\r
-      strcpyW(This->pwcsName, pwcsName);\r
-  }\r
-\r
-  /*\r
-   * Initialize the big block cache.\r
-   */\r
-  This->bigBlockSize   = DEF_BIG_BLOCK_SIZE;\r
-  This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;\r
-  This->bigBlockFile   = BIGBLOCKFILE_Construct(hFile,\r
-                                                pLkbyt,\r
-                                                openFlags,\r
-                                                This->bigBlockSize,\r
-                                                fileBased);\r
-\r
-  if (This->bigBlockFile == 0)\r
-    return E_FAIL;\r
-\r
-  if (fileCreate)\r
-  {\r
-    ULARGE_INTEGER size;\r
-    BYTE* bigBlockBuffer;\r
-\r
-    /*\r
-     * Initialize all header variables:\r
-     * - The big block depot consists of one block and it is at block 0\r
-     * - The properties start at block 1\r
-     * - There is no small block depot\r
-     */\r
-    memset( This->bigBlockDepotStart,\r
-            BLOCK_UNUSED,\r
-            sizeof(This->bigBlockDepotStart));\r
-\r
-    This->bigBlockDepotCount    = 1;\r
-    This->bigBlockDepotStart[0] = 0;\r
-    This->rootStartBlock        = 1;\r
-    This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;\r
-    This->bigBlockSizeBits      = DEF_BIG_BLOCK_SIZE_BITS;\r
-    This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;\r
-    This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;\r
-    This->extBigBlockDepotCount = 0;\r
-\r
-    StorageImpl_SaveFileHeader(This);\r
-\r
-    /*\r
-     * Add one block for the big block depot and one block for the properties\r
-     */\r
-    size.u.HighPart = 0;\r
-    size.u.LowPart  = This->bigBlockSize * 3;\r
-    BIGBLOCKFILE_SetSize(This->bigBlockFile, size);\r
-\r
-    /*\r
-     * Initialize the big block depot\r
-     */\r
-    bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);\r
-    memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);\r
-    StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);\r
-    StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);\r
-    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);\r
-  }\r
-  else\r
-  {\r
-    /*\r
-     * Load the header for the file.\r
-     */\r
-    hr = StorageImpl_LoadFileHeader(This);\r
-\r
-    if (FAILED(hr))\r
-    {\r
-      BIGBLOCKFILE_Destructor(This->bigBlockFile);\r
-\r
-      return hr;\r
-    }\r
-  }\r
-\r
-  /*\r
-   * There is no block depot cached yet.\r
-   */\r
-  This->indexBlockDepotCached = 0xFFFFFFFF;\r
-\r
-  /*\r
-   * Start searching for free blocks with block 0.\r
-   */\r
-  This->prevFreeBlock = 0;\r
-\r
-  /*\r
-   * Create the block chain abstractions.\r
-   */\r
-  if(!(This->rootBlockChain =\r
-       BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL)))\r
-    return STG_E_READFAULT;\r
-\r
-  if(!(This->smallBlockDepotChain =\r
-       BlockChainStream_Construct(This, &This->smallBlockDepotStart,\r
-                                 PROPERTY_NULL)))\r
-    return STG_E_READFAULT;\r
-\r
-  /*\r
-   * Write the root property\r
-   */\r
-  if (fileCreate)\r
-  {\r
-    StgProperty rootProp;\r
-    /*\r
-     * Initialize the property chain\r
-     */\r
-    memset(&rootProp, 0, sizeof(rootProp));\r
-    MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name,\r
-                         sizeof(rootProp.name)/sizeof(WCHAR) );\r
-    rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR);\r
-    rootProp.propertyType     = PROPTYPE_ROOT;\r
-    rootProp.previousProperty = PROPERTY_NULL;\r
-    rootProp.nextProperty     = PROPERTY_NULL;\r
-    rootProp.dirProperty      = PROPERTY_NULL;\r
-    rootProp.startingBlock    = BLOCK_END_OF_CHAIN;\r
-    rootProp.size.u.HighPart    = 0;\r
-    rootProp.size.u.LowPart     = 0;\r
-\r
-    StorageImpl_WriteProperty(This, 0, &rootProp);\r
-  }\r
-\r
-  /*\r
-   * Find the ID of the root in the property sets.\r
-   */\r
-  currentPropertyIndex = 0;\r
-\r
-  do\r
-  {\r
-    readSuccessful = StorageImpl_ReadProperty(\r
-                      This,\r
-                      currentPropertyIndex,\r
-                      &currentProperty);\r
-\r
-    if (readSuccessful)\r
-    {\r
-      if ( (currentProperty.sizeOfNameString != 0 ) &&\r
-           (currentProperty.propertyType     == PROPTYPE_ROOT) )\r
-      {\r
-        This->base.rootPropertySetIndex = currentPropertyIndex;\r
-      }\r
-    }\r
-\r
-    currentPropertyIndex++;\r
-\r
-  } while (readSuccessful && (This->base.rootPropertySetIndex == PROPERTY_NULL) );\r
-\r
-  if (!readSuccessful)\r
-  {\r
-    /* TODO CLEANUP */\r
-    return STG_E_READFAULT;\r
-  }\r
-\r
-  /*\r
-   * Create the block chain abstraction for the small block root chain.\r
-   */\r
-  if(!(This->smallBlockRootChain =\r
-       BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex)))\r
-    return STG_E_READFAULT;\r
-\r
-  return hr;\r
-}\r
-\r
-void StorageImpl_Destroy(StorageBaseImpl* iface)\r
-{\r
-  StorageImpl *This = (StorageImpl*) iface;\r
-  TRACE("(%p)\n", This);\r
-\r
-  HeapFree(GetProcessHeap(), 0, This->pwcsName);\r
-\r
-  BlockChainStream_Destroy(This->smallBlockRootChain);\r
-  BlockChainStream_Destroy(This->rootBlockChain);\r
-  BlockChainStream_Destroy(This->smallBlockDepotChain);\r
-\r
-  BIGBLOCKFILE_Destructor(This->bigBlockFile);\r
-  HeapFree(GetProcessHeap(), 0, This);\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_GetNextFreeBigBlock\r
- *\r
- * Returns the index of the next free big block.\r
- * If the big block depot is filled, this method will enlarge it.\r
- *\r
- */\r
-ULONG StorageImpl_GetNextFreeBigBlock(\r
-  StorageImpl* This)\r
-{\r
-  ULONG depotBlockIndexPos;\r
-  void  *depotBuffer;\r
-  ULONG depotBlockOffset;\r
-  ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);\r
-  ULONG nextBlockIndex    = BLOCK_SPECIAL;\r
-  int   depotIndex        = 0;\r
-  ULONG freeBlock         = BLOCK_UNUSED;\r
-\r
-  depotIndex = This->prevFreeBlock / blocksPerDepot;\r
-  depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);\r
-\r
-  /*\r
-   * Scan the entire big block depot until we find a block marked free\r
-   */\r
-  while (nextBlockIndex != BLOCK_UNUSED)\r
-  {\r
-    if (depotIndex < COUNT_BBDEPOTINHEADER)\r
-    {\r
-      depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];\r
-\r
-      /*\r
-       * Grow the primary depot.\r
-       */\r
-      if (depotBlockIndexPos == BLOCK_UNUSED)\r
-      {\r
-        depotBlockIndexPos = depotIndex*blocksPerDepot;\r
-\r
-        /*\r
-         * Add a block depot.\r
-         */\r
-        Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);\r
-        This->bigBlockDepotCount++;\r
-        This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;\r
-\r
-        /*\r
-         * Flag it as a block depot.\r
-         */\r
-        StorageImpl_SetNextBlockInChain(This,\r
-                                          depotBlockIndexPos,\r
-                                          BLOCK_SPECIAL);\r
-\r
-        /* Save new header information.\r
-         */\r
-        StorageImpl_SaveFileHeader(This);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);\r
-\r
-      if (depotBlockIndexPos == BLOCK_UNUSED)\r
-      {\r
-        /*\r
-         * Grow the extended depot.\r
-         */\r
-        ULONG extIndex       = BLOCK_UNUSED;\r
-        ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;\r
-        ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);\r
-\r
-        if (extBlockOffset == 0)\r
-        {\r
-          /* We need an extended block.\r
-           */\r
-          extIndex = Storage32Impl_AddExtBlockDepot(This);\r
-          This->extBigBlockDepotCount++;\r
-          depotBlockIndexPos = extIndex + 1;\r
-        }\r
-        else\r
-          depotBlockIndexPos = depotIndex * blocksPerDepot;\r
-\r
-        /*\r
-         * Add a block depot and mark it in the extended block.\r
-         */\r
-        Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);\r
-        This->bigBlockDepotCount++;\r
-        Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);\r
-\r
-        /* Flag the block depot.\r
-         */\r
-        StorageImpl_SetNextBlockInChain(This,\r
-                                          depotBlockIndexPos,\r
-                                          BLOCK_SPECIAL);\r
-\r
-        /* If necessary, flag the extended depot block.\r
-         */\r
-        if (extIndex != BLOCK_UNUSED)\r
-          StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);\r
-\r
-        /* Save header information.\r
-         */\r
-        StorageImpl_SaveFileHeader(This);\r
-      }\r
-    }\r
-\r
-    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);\r
-\r
-    if (depotBuffer != 0)\r
-    {\r
-      while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&\r
-              ( nextBlockIndex != BLOCK_UNUSED))\r
-      {\r
-        StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);\r
-\r
-        if (nextBlockIndex == BLOCK_UNUSED)\r
-        {\r
-          freeBlock = (depotIndex * blocksPerDepot) +\r
-                      (depotBlockOffset/sizeof(ULONG));\r
-        }\r
-\r
-        depotBlockOffset += sizeof(ULONG);\r
-      }\r
-\r
-      StorageImpl_ReleaseBigBlock(This, depotBuffer);\r
-    }\r
-\r
-    depotIndex++;\r
-    depotBlockOffset = 0;\r
-  }\r
-\r
-  This->prevFreeBlock = freeBlock;\r
-\r
-  return freeBlock;\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_AddBlockDepot\r
- *\r
- * This will create a depot block, essentially it is a block initialized\r
- * to BLOCK_UNUSEDs.\r
- */\r
-void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)\r
-{\r
-  BYTE* blockBuffer;\r
-\r
-  blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);\r
-\r
-  /*\r
-   * Initialize blocks as free\r
-   */\r
-  memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);\r
-\r
-  StorageImpl_ReleaseBigBlock(This, blockBuffer);\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_GetExtDepotBlock\r
- *\r
- * Returns the index of the block that corresponds to the specified depot\r
- * index. This method is only for depot indexes equal or greater than\r
- * COUNT_BBDEPOTINHEADER.\r
- */\r
-ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)\r
-{\r
-  ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;\r
-  ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;\r
-  ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;\r
-  ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;\r
-  ULONG blockIndex             = BLOCK_UNUSED;\r
-  ULONG extBlockIndex          = This->extBigBlockDepotStart;\r
-\r
-  assert(depotIndex >= COUNT_BBDEPOTINHEADER);\r
-\r
-  if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)\r
-    return BLOCK_UNUSED;\r
-\r
-  while (extBlockCount > 0)\r
-  {\r
-    extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);\r
-    extBlockCount--;\r
-  }\r
-\r
-  if (extBlockIndex != BLOCK_UNUSED)\r
-  {\r
-    BYTE* depotBuffer;\r
-\r
-    depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);\r
-\r
-    if (depotBuffer != 0)\r
-    {\r
-      StorageUtl_ReadDWord(depotBuffer,\r
-                           extBlockOffset * sizeof(ULONG),\r
-                           &blockIndex);\r
-\r
-      StorageImpl_ReleaseBigBlock(This, depotBuffer);\r
-    }\r
-  }\r
-\r
-  return blockIndex;\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_SetExtDepotBlock\r
- *\r
- * Associates the specified block index to the specified depot index.\r
- * This method is only for depot indexes equal or greater than\r
- * COUNT_BBDEPOTINHEADER.\r
- */\r
-void Storage32Impl_SetExtDepotBlock(StorageImpl* This,\r
-                                    ULONG depotIndex,\r
-                                    ULONG blockIndex)\r
-{\r
-  ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;\r
-  ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;\r
-  ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;\r
-  ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;\r
-  ULONG extBlockIndex          = This->extBigBlockDepotStart;\r
-\r
-  assert(depotIndex >= COUNT_BBDEPOTINHEADER);\r
-\r
-  while (extBlockCount > 0)\r
-  {\r
-    extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);\r
-    extBlockCount--;\r
-  }\r
-\r
-  if (extBlockIndex != BLOCK_UNUSED)\r
-  {\r
-    BYTE* depotBuffer;\r
-\r
-    depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);\r
-\r
-    if (depotBuffer != 0)\r
-    {\r
-      StorageUtl_WriteDWord(depotBuffer,\r
-                            extBlockOffset * sizeof(ULONG),\r
-                            blockIndex);\r
-\r
-      StorageImpl_ReleaseBigBlock(This, depotBuffer);\r
-    }\r
-  }\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_AddExtBlockDepot\r
- *\r
- * Creates an extended depot block.\r
- */\r
-ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)\r
-{\r
-  ULONG numExtBlocks           = This->extBigBlockDepotCount;\r
-  ULONG nextExtBlock           = This->extBigBlockDepotStart;\r
-  BYTE* depotBuffer            = NULL;\r
-  ULONG index                  = BLOCK_UNUSED;\r
-  ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);\r
-  ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);\r
-  ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;\r
-\r
-  index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *\r
-          blocksPerDepotBlock;\r
-\r
-  if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))\r
-  {\r
-    /*\r
-     * The first extended block.\r
-     */\r
-    This->extBigBlockDepotStart = index;\r
-  }\r
-  else\r
-  {\r
-    unsigned int i;\r
-    /*\r
-     * Follow the chain to the last one.\r
-     */\r
-    for (i = 0; i < (numExtBlocks - 1); i++)\r
-    {\r
-      nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);\r
-    }\r
-\r
-    /*\r
-     * Add the new extended block to the chain.\r
-     */\r
-    depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);\r
-    StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);\r
-    StorageImpl_ReleaseBigBlock(This, depotBuffer);\r
-  }\r
-\r
-  /*\r
-   * Initialize this block.\r
-   */\r
-  depotBuffer = StorageImpl_GetBigBlock(This, index);\r
-  memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);\r
-  StorageImpl_ReleaseBigBlock(This, depotBuffer);\r
-\r
-  return index;\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_FreeBigBlock\r
- *\r
- * This method will flag the specified block as free in the big block depot.\r
- */\r
-void  StorageImpl_FreeBigBlock(\r
-  StorageImpl* This,\r
-  ULONG          blockIndex)\r
-{\r
-  StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);\r
-\r
-  if (blockIndex < This->prevFreeBlock)\r
-    This->prevFreeBlock = blockIndex;\r
-}\r
-\r
-/************************************************************************\r
- * Storage32Impl_GetNextBlockInChain\r
- *\r
- * This method will retrieve the block index of the next big block in\r
- * in the chain.\r
- *\r
- * Params:  This       - Pointer to the Storage object.\r
- *          blockIndex - Index of the block to retrieve the chain\r
- *                       for.\r
- *          nextBlockIndex - receives the return value.\r
- *\r
- * Returns: This method returns the index of the next block in the chain.\r
- *          It will return the constants:\r
- *              BLOCK_SPECIAL - If the block given was not part of a\r
- *                              chain.\r
- *              BLOCK_END_OF_CHAIN - If the block given was the last in\r
- *                                   a chain.\r
- *              BLOCK_UNUSED - If the block given was not past of a chain\r
- *                             and is available.\r
- *              BLOCK_EXTBBDEPOT - This block is part of the extended\r
- *                                 big block depot.\r
- *\r
- * See Windows documentation for more details on IStorage methods.\r
- */\r
-HRESULT StorageImpl_GetNextBlockInChain(\r
-  StorageImpl* This,\r
-  ULONG        blockIndex,\r
-  ULONG*       nextBlockIndex)\r
-{\r
-  ULONG offsetInDepot    = blockIndex * sizeof (ULONG);\r
-  ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;\r
-  ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;\r
-  void* depotBuffer;\r
-  ULONG depotBlockIndexPos;\r
-  int index;\r
-\r
-  *nextBlockIndex   = BLOCK_SPECIAL;\r
-\r
-  if(depotBlockCount >= This->bigBlockDepotCount)\r
-  {\r
-    WARN("depotBlockCount %ld, bigBlockDepotCount %ld\n", depotBlockCount,\r
-        This->bigBlockDepotCount);\r
-    return STG_E_READFAULT;\r
-  }\r
-\r
-  /*\r
-   * Cache the currently accessed depot block.\r
-   */\r
-  if (depotBlockCount != This->indexBlockDepotCached)\r
-  {\r
-    This->indexBlockDepotCached = depotBlockCount;\r
-\r
-    if (depotBlockCount < COUNT_BBDEPOTINHEADER)\r
-    {\r
-      depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];\r
-    }\r
-    else\r
-    {\r
-      /*\r
-       * We have to look in the extended depot.\r
-       */\r
-      depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);\r
-    }\r
-\r
-    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);\r
-\r
-    if (!depotBuffer)\r
-      return STG_E_READFAULT;\r
-\r
-    for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)\r
-    {\r
-      StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);\r
-      This->blockDepotCached[index] = *nextBlockIndex;\r
-    }\r
-    StorageImpl_ReleaseBigBlock(This, depotBuffer);\r
-  }\r
-\r
-  *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];\r
-\r
-  return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_GetNextExtendedBlock\r
- *\r
- * Given an extended block this method will return the next extended block.\r
- *\r
- * NOTES:\r
- * The last ULONG of an extended block is the block index of the next\r
- * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the\r
- * depot.\r
- *\r
- * Return values:\r
- *    - The index of the next extended block\r
- *    - BLOCK_UNUSED: there is no next extended block.\r
- *    - Any other return values denotes failure.\r
- */\r
-ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)\r
-{\r
-  ULONG nextBlockIndex   = BLOCK_SPECIAL;\r
-  ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);\r
-  void* depotBuffer;\r
-\r
-  depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);\r
-\r
-  if (depotBuffer!=0)\r
-  {\r
-    StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);\r
-\r
-    StorageImpl_ReleaseBigBlock(This, depotBuffer);\r
-  }\r
-\r
-  return nextBlockIndex;\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_SetNextBlockInChain\r
- *\r
- * This method will write the index of the specified block's next block\r
- * in the big block depot.\r
- *\r
- * For example: to create the chain 3 -> 1 -> 7 -> End of Chain\r
- *              do the following\r
- *\r
- * Storage32Impl_SetNextBlockInChain(This, 3, 1);\r
- * Storage32Impl_SetNextBlockInChain(This, 1, 7);\r
- * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);\r
- *\r
- */\r
-void  StorageImpl_SetNextBlockInChain(\r
-          StorageImpl* This,\r
-          ULONG          blockIndex,\r
-          ULONG          nextBlock)\r
-{\r
-  ULONG offsetInDepot    = blockIndex * sizeof (ULONG);\r
-  ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;\r
-  ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;\r
-  ULONG depotBlockIndexPos;\r
-  void* depotBuffer;\r
-\r
-  assert(depotBlockCount < This->bigBlockDepotCount);\r
-  assert(blockIndex != nextBlock);\r
-\r
-  if (depotBlockCount < COUNT_BBDEPOTINHEADER)\r
-  {\r
-    depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];\r
-  }\r
-  else\r
-  {\r
-    /*\r
-     * We have to look in the extended depot.\r
-     */\r
-    depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);\r
-  }\r
-\r
-  depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);\r
-\r
-  if (depotBuffer!=0)\r
-  {\r
-    StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);\r
-    StorageImpl_ReleaseBigBlock(This, depotBuffer);\r
-  }\r
-\r
-  /*\r
-   * Update the cached block depot, if necessary.\r
-   */\r
-  if (depotBlockCount == This->indexBlockDepotCached)\r
-  {\r
-    This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;\r
-  }\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_LoadFileHeader\r
- *\r
- * This method will read in the file header, i.e. big block index -1.\r
- */\r
-HRESULT StorageImpl_LoadFileHeader(\r
-          StorageImpl* This)\r
-{\r
-  HRESULT hr = STG_E_FILENOTFOUND;\r
-  void*   headerBigBlock = NULL;\r
-  int     index;\r
-\r
-  /*\r
-   * Get a pointer to the big block of data containing the header.\r
-   */\r
-  headerBigBlock = StorageImpl_GetROBigBlock(This, -1);\r
-\r
-  /*\r
-   * Extract the information from the header.\r
-   */\r
-  if (headerBigBlock!=0)\r
-  {\r
-    /*\r
-     * Check for the "magic number" signature and return an error if it is not\r
-     * found.\r
-     */\r
-    if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)\r
-    {\r
-      StorageImpl_ReleaseBigBlock(This, headerBigBlock);\r
-      return STG_E_OLDFORMAT;\r
-    }\r
-\r
-    if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)\r
-    {\r
-      StorageImpl_ReleaseBigBlock(This, headerBigBlock);\r
-      return STG_E_INVALIDHEADER;\r
-    }\r
-\r
-    StorageUtl_ReadWord(\r
-      headerBigBlock,\r
-      OFFSET_BIGBLOCKSIZEBITS,\r
-      &This->bigBlockSizeBits);\r
-\r
-    StorageUtl_ReadWord(\r
-      headerBigBlock,\r
-      OFFSET_SMALLBLOCKSIZEBITS,\r
-      &This->smallBlockSizeBits);\r
-\r
-    StorageUtl_ReadDWord(\r
-      headerBigBlock,\r
-      OFFSET_BBDEPOTCOUNT,\r
-      &This->bigBlockDepotCount);\r
-\r
-    StorageUtl_ReadDWord(\r
-      headerBigBlock,\r
-      OFFSET_ROOTSTARTBLOCK,\r
-      &This->rootStartBlock);\r
-\r
-    StorageUtl_ReadDWord(\r
-      headerBigBlock,\r
-      OFFSET_SBDEPOTSTART,\r
-      &This->smallBlockDepotStart);\r
-\r
-    StorageUtl_ReadDWord(\r
-      headerBigBlock,\r
-      OFFSET_EXTBBDEPOTSTART,\r
-      &This->extBigBlockDepotStart);\r
-\r
-    StorageUtl_ReadDWord(\r
-      headerBigBlock,\r
-      OFFSET_EXTBBDEPOTCOUNT,\r
-      &This->extBigBlockDepotCount);\r
-\r
-    for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)\r
-    {\r
-      StorageUtl_ReadDWord(\r
-        headerBigBlock,\r
-        OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),\r
-        &(This->bigBlockDepotStart[index]));\r
-    }\r
-\r
-    /*\r
-     * Make the bitwise arithmetic to get the size of the blocks in bytes.\r
-     */\r
-    if ((1 << 2) == 4)\r
-    {\r
-      This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;\r
-      This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;\r
-    }\r
-    else\r
-    {\r
-      This->bigBlockSize   = 0x000000001 >> (DWORD)This->bigBlockSizeBits;\r
-      This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;\r
-    }\r
-\r
-    /*\r
-     * Right now, the code is making some assumptions about the size of the\r
-     * blocks, just make sure they are what we're expecting.\r
-     */\r
-    if (This->bigBlockSize != DEF_BIG_BLOCK_SIZE ||\r
-       This->smallBlockSize != DEF_SMALL_BLOCK_SIZE)\r
-    {\r
-       WARN("Broken OLE storage file\n");\r
-       hr = STG_E_INVALIDHEADER;\r
-    }\r
-    else\r
-       hr = S_OK;\r
-\r
-    /*\r
-     * Release the block.\r
-     */\r
-    StorageImpl_ReleaseBigBlock(This, headerBigBlock);\r
-  }\r
-\r
-  return hr;\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_SaveFileHeader\r
- *\r
- * This method will save to the file the header, i.e. big block -1.\r
- */\r
-void StorageImpl_SaveFileHeader(\r
-          StorageImpl* This)\r
-{\r
-  BYTE   headerBigBlock[BIG_BLOCK_SIZE];\r
-  int    index;\r
-  BOOL success;\r
-\r
-  /*\r
-   * Get a pointer to the big block of data containing the header.\r
-   */\r
-  success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);\r
-\r
-  /*\r
-   * If the block read failed, the file is probably new.\r
-   */\r
-  if (!success)\r
-  {\r
-    /*\r
-     * Initialize for all unknown fields.\r
-     */\r
-    memset(headerBigBlock, 0, BIG_BLOCK_SIZE);\r
-\r
-    /*\r
-     * Initialize the magic number.\r
-     */\r
-    memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));\r
-\r
-    /*\r
-     * And a bunch of things we don't know what they mean\r
-     */\r
-    StorageUtl_WriteWord(headerBigBlock,  0x18, 0x3b);\r
-    StorageUtl_WriteWord(headerBigBlock,  0x1a, 0x3);\r
-    StorageUtl_WriteWord(headerBigBlock,  0x1c, (WORD)-2);\r
-    StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);\r
-  }\r
-\r
-  /*\r
-   * Write the information to the header.\r
-   */\r
-  StorageUtl_WriteWord(\r
-    headerBigBlock,\r
-    OFFSET_BIGBLOCKSIZEBITS,\r
-    This->bigBlockSizeBits);\r
-\r
-  StorageUtl_WriteWord(\r
-    headerBigBlock,\r
-    OFFSET_SMALLBLOCKSIZEBITS,\r
-    This->smallBlockSizeBits);\r
-\r
-  StorageUtl_WriteDWord(\r
-    headerBigBlock,\r
-    OFFSET_BBDEPOTCOUNT,\r
-    This->bigBlockDepotCount);\r
-\r
-  StorageUtl_WriteDWord(\r
-    headerBigBlock,\r
-    OFFSET_ROOTSTARTBLOCK,\r
-    This->rootStartBlock);\r
-\r
-  StorageUtl_WriteDWord(\r
-    headerBigBlock,\r
-    OFFSET_SBDEPOTSTART,\r
-    This->smallBlockDepotStart);\r
-\r
-  StorageUtl_WriteDWord(\r
-    headerBigBlock,\r
-    OFFSET_SBDEPOTCOUNT,\r
-    This->smallBlockDepotChain ?\r
-     BlockChainStream_GetCount(This->smallBlockDepotChain) : 0);\r
-\r
-  StorageUtl_WriteDWord(\r
-    headerBigBlock,\r
-    OFFSET_EXTBBDEPOTSTART,\r
-    This->extBigBlockDepotStart);\r
-\r
-  StorageUtl_WriteDWord(\r
-    headerBigBlock,\r
-    OFFSET_EXTBBDEPOTCOUNT,\r
-    This->extBigBlockDepotCount);\r
-\r
-  for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)\r
-  {\r
-    StorageUtl_WriteDWord(\r
-      headerBigBlock,\r
-      OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),\r
-      (This->bigBlockDepotStart[index]));\r
-  }\r
-\r
-  /*\r
-   * Write the big block back to the file.\r
-   */\r
-  StorageImpl_WriteBigBlock(This, -1, headerBigBlock);\r
-}\r
-\r
-/******************************************************************************\r
- *      Storage32Impl_ReadProperty\r
- *\r
- * This method will read the specified property from the property chain.\r
- */\r
-BOOL StorageImpl_ReadProperty(\r
-  StorageImpl* This,\r
-  ULONG          index,\r
-  StgProperty*   buffer)\r
-{\r
-  BYTE           currentProperty[PROPSET_BLOCK_SIZE];\r
-  ULARGE_INTEGER offsetInPropSet;\r
-  BOOL         readSuccessful;\r
-  ULONG          bytesRead;\r
-\r
-  offsetInPropSet.u.HighPart = 0;\r
-  offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;\r
-\r
-  readSuccessful = BlockChainStream_ReadAt(\r
-                    This->rootBlockChain,\r
-                    offsetInPropSet,\r
-                    PROPSET_BLOCK_SIZE,\r
-                    currentProperty,\r
-                    &bytesRead);\r
-\r
-  if (readSuccessful)\r
-  {\r
-    /* replace the name of root entry (often "Root Entry") by the file name */\r
-    WCHAR *propName = (index == This->base.rootPropertySetIndex) ?\r
-                       This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME;\r
-\r
-    memset(buffer->name, 0, sizeof(buffer->name));\r
-    memcpy(\r
-      buffer->name,\r
-      propName,\r
-      PROPERTY_NAME_BUFFER_LEN );\r
-    TRACE("storage name: %s\n", debugstr_w(buffer->name));\r
-\r
-    memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);\r
-\r
-    StorageUtl_ReadWord(\r
-      currentProperty,\r
-      OFFSET_PS_NAMELENGTH,\r
-      &buffer->sizeOfNameString);\r
-\r
-    StorageUtl_ReadDWord(\r
-      currentProperty,\r
-      OFFSET_PS_PREVIOUSPROP,\r
-      &buffer->previousProperty);\r
-\r
-    StorageUtl_ReadDWord(\r
-      currentProperty,\r
-      OFFSET_PS_NEXTPROP,\r
-      &buffer->nextProperty);\r
-\r
-    StorageUtl_ReadDWord(\r
-      currentProperty,\r
-      OFFSET_PS_DIRPROP,\r
-      &buffer->dirProperty);\r
-\r
-    StorageUtl_ReadGUID(\r
-      currentProperty,\r
-      OFFSET_PS_GUID,\r
-      &buffer->propertyUniqueID);\r
-\r
-    StorageUtl_ReadDWord(\r
-      currentProperty,\r
-      OFFSET_PS_TSS1,\r
-      &buffer->timeStampS1);\r
-\r
-    StorageUtl_ReadDWord(\r
-      currentProperty,\r
-      OFFSET_PS_TSD1,\r
-      &buffer->timeStampD1);\r
-\r
-    StorageUtl_ReadDWord(\r
-      currentProperty,\r
-      OFFSET_PS_TSS2,\r
-      &buffer->timeStampS2);\r
-\r
-    StorageUtl_ReadDWord(\r
-      currentProperty,\r
-      OFFSET_PS_TSD2,\r
-      &buffer->timeStampD2);\r
-\r
-    StorageUtl_ReadDWord(\r
-      currentProperty,\r
-      OFFSET_PS_STARTBLOCK,\r
-      &buffer->startingBlock);\r
-\r
-    StorageUtl_ReadDWord(\r
-      currentProperty,\r
-      OFFSET_PS_SIZE,\r
-      &buffer->size.u.LowPart);\r
-\r
-    buffer->size.u.HighPart = 0;\r
-  }\r
-\r
-  return readSuccessful;\r
-}\r
-\r
-/*********************************************************************\r
- * Write the specified property into the property chain\r
- */\r
-BOOL StorageImpl_WriteProperty(\r
-  StorageImpl* This,\r
-  ULONG          index,\r
-  StgProperty*   buffer)\r
-{\r
-  BYTE           currentProperty[PROPSET_BLOCK_SIZE];\r
-  ULARGE_INTEGER offsetInPropSet;\r
-  BOOL         writeSuccessful;\r
-  ULONG          bytesWritten;\r
-\r
-  offsetInPropSet.u.HighPart = 0;\r
-  offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;\r
-\r
-  memset(currentProperty, 0, PROPSET_BLOCK_SIZE);\r
-\r
-  memcpy(\r
-    currentProperty + OFFSET_PS_NAME,\r
-    buffer->name,\r
-    PROPERTY_NAME_BUFFER_LEN );\r
-\r
-  memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);\r
-\r
-  StorageUtl_WriteWord(\r
-    currentProperty,\r
-      OFFSET_PS_NAMELENGTH,\r
-      buffer->sizeOfNameString);\r
-\r
-  StorageUtl_WriteDWord(\r
-    currentProperty,\r
-      OFFSET_PS_PREVIOUSPROP,\r
-      buffer->previousProperty);\r
-\r
-  StorageUtl_WriteDWord(\r
-    currentProperty,\r
-      OFFSET_PS_NEXTPROP,\r
-      buffer->nextProperty);\r
-\r
-  StorageUtl_WriteDWord(\r
-    currentProperty,\r
-      OFFSET_PS_DIRPROP,\r
-      buffer->dirProperty);\r
-\r
-  StorageUtl_WriteGUID(\r
-    currentProperty,\r
-      OFFSET_PS_GUID,\r
-      &buffer->propertyUniqueID);\r
-\r
-  StorageUtl_WriteDWord(\r
-    currentProperty,\r
-      OFFSET_PS_TSS1,\r
-      buffer->timeStampS1);\r
-\r
-  StorageUtl_WriteDWord(\r
-    currentProperty,\r
-      OFFSET_PS_TSD1,\r
-      buffer->timeStampD1);\r
-\r
-  StorageUtl_WriteDWord(\r
-    currentProperty,\r
-      OFFSET_PS_TSS2,\r
-      buffer->timeStampS2);\r
-\r
-  StorageUtl_WriteDWord(\r
-    currentProperty,\r
-      OFFSET_PS_TSD2,\r
-      buffer->timeStampD2);\r
-\r
-  StorageUtl_WriteDWord(\r
-    currentProperty,\r
-      OFFSET_PS_STARTBLOCK,\r
-      buffer->startingBlock);\r
-\r
-  StorageUtl_WriteDWord(\r
-    currentProperty,\r
-      OFFSET_PS_SIZE,\r
-      buffer->size.u.LowPart);\r
-\r
-  writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain,\r
-                                            offsetInPropSet,\r
-                                            PROPSET_BLOCK_SIZE,\r
-                                            currentProperty,\r
-                                            &bytesWritten);\r
-  return writeSuccessful;\r
-}\r
-\r
-BOOL StorageImpl_ReadBigBlock(\r
-  StorageImpl* This,\r
-  ULONG          blockIndex,\r
-  void*          buffer)\r
-{\r
-  void* bigBlockBuffer;\r
-\r
-  bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);\r
-\r
-  if (bigBlockBuffer!=0)\r
-  {\r
-    memcpy(buffer, bigBlockBuffer, This->bigBlockSize);\r
-\r
-    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);\r
-\r
-    return TRUE;\r
-  }\r
-\r
-  return FALSE;\r
-}\r
-\r
-BOOL StorageImpl_WriteBigBlock(\r
-  StorageImpl* This,\r
-  ULONG          blockIndex,\r
-  void*          buffer)\r
-{\r
-  void* bigBlockBuffer;\r
-\r
-  bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);\r
-\r
-  if (bigBlockBuffer!=0)\r
-  {\r
-    memcpy(bigBlockBuffer, buffer, This->bigBlockSize);\r
-\r
-    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);\r
-\r
-    return TRUE;\r
-  }\r
-\r
-  return FALSE;\r
-}\r
-\r
-void* StorageImpl_GetROBigBlock(\r
-  StorageImpl* This,\r
-  ULONG          blockIndex)\r
-{\r
-  return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);\r
-}\r
-\r
-void* StorageImpl_GetBigBlock(\r
-  StorageImpl* This,\r
-  ULONG          blockIndex)\r
-{\r
-  return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);\r
-}\r
-\r
-void StorageImpl_ReleaseBigBlock(\r
-  StorageImpl* This,\r
-  void*          pBigBlock)\r
-{\r
-  BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);\r
-}\r
-\r
-/******************************************************************************\r
- *              Storage32Impl_SmallBlocksToBigBlocks\r
- *\r
- * This method will convert a small block chain to a big block chain.\r
- * The small block chain will be destroyed.\r
- */\r
-BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(\r
-                      StorageImpl* This,\r
-                      SmallBlockChainStream** ppsbChain)\r
-{\r
-  ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;\r
-  ULARGE_INTEGER size, offset;\r
-  ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;\r
-  ULONG propertyIndex;\r
-  BOOL successRead, successWrite;\r
-  StgProperty chainProperty;\r
-  BYTE *buffer;\r
-  BlockChainStream *bbTempChain = NULL;\r
-  BlockChainStream *bigBlockChain = NULL;\r
-\r
-  /*\r
-   * Create a temporary big block chain that doesn't have\r
-   * an associated property. This temporary chain will be\r
-   * used to copy data from small blocks to big blocks.\r
-   */\r
-  bbTempChain = BlockChainStream_Construct(This,\r
-                                           &bbHeadOfChain,\r
-                                           PROPERTY_NULL);\r
-  if(!bbTempChain) return NULL;\r
-  /*\r
-   * Grow the big block chain.\r
-   */\r
-  size = SmallBlockChainStream_GetSize(*ppsbChain);\r
-  BlockChainStream_SetSize(bbTempChain, size);\r
-\r
-  /*\r
-   * Copy the contents of the small block chain to the big block chain\r
-   * by small block size increments.\r
-   */\r
-  offset.u.LowPart = 0;\r
-  offset.u.HighPart = 0;\r
-  cbTotalRead = 0;\r
-  cbTotalWritten = 0;\r
-\r
-  buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);\r
-  do\r
-  {\r
-    successRead = SmallBlockChainStream_ReadAt(*ppsbChain,\r
-                                               offset,\r
-                                               DEF_SMALL_BLOCK_SIZE,\r
-                                               buffer,\r
-                                               &cbRead);\r
-    cbTotalRead += cbRead;\r
-\r
-    successWrite = BlockChainStream_WriteAt(bbTempChain,\r
-                                            offset,\r
-                                            cbRead,\r
-                                            buffer,\r
-                                            &cbWritten);\r
-    cbTotalWritten += cbWritten;\r
-\r
-    offset.u.LowPart += This->smallBlockSize;\r
-\r
-  } while (successRead && successWrite);\r
-  HeapFree(GetProcessHeap(),0,buffer);\r
-\r
-  assert(cbTotalRead == cbTotalWritten);\r
-\r
-  /*\r
-   * Destroy the small block chain.\r
-   */\r
-  propertyIndex = (*ppsbChain)->ownerPropertyIndex;\r
-  size.u.HighPart = 0;\r
-  size.u.LowPart  = 0;\r
-  SmallBlockChainStream_SetSize(*ppsbChain, size);\r
-  SmallBlockChainStream_Destroy(*ppsbChain);\r
-  *ppsbChain = 0;\r
-\r
-  /*\r
-   * Change the property information. This chain is now a big block chain\r
-   * and it doesn't reside in the small blocks chain anymore.\r
-   */\r
-  StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);\r
-\r
-  chainProperty.startingBlock = bbHeadOfChain;\r
-\r
-  StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);\r
-\r
-  /*\r
-   * Destroy the temporary propertyless big block chain.\r
-   * Create a new big block chain associated with this property.\r
-   */\r
-  BlockChainStream_Destroy(bbTempChain);\r
-  bigBlockChain = BlockChainStream_Construct(This,\r
-                                             NULL,\r
-                                             propertyIndex);\r
-\r
-  return bigBlockChain;\r
-}\r
-\r
-void StorageInternalImpl_Destroy( StorageBaseImpl *iface)\r
-{\r
-  StorageInternalImpl* This = (StorageInternalImpl*) iface;\r
-\r
-  StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage);\r
-  HeapFree(GetProcessHeap(), 0, This);\r
-}\r
-\r
-/******************************************************************************\r
-**\r
-** Storage32InternalImpl_Commit\r
-**\r
-** The non-root storages cannot be opened in transacted mode thus this function\r
-** does nothing.\r
-*/\r
-HRESULT WINAPI StorageInternalImpl_Commit(\r
-  IStorage*            iface,\r
-  DWORD                  grfCommitFlags)  /* [in] */\r
-{\r
-  return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
-**\r
-** Storage32InternalImpl_Revert\r
-**\r
-** The non-root storages cannot be opened in transacted mode thus this function\r
-** does nothing.\r
-*/\r
-HRESULT WINAPI StorageInternalImpl_Revert(\r
-  IStorage*            iface)\r
-{\r
-  return S_OK;\r
-}\r
-\r
-void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)\r
-{\r
-  IStorage_Release((IStorage*)This->parentStorage);\r
-  HeapFree(GetProcessHeap(), 0, This->stackToVisit);\r
-  HeapFree(GetProcessHeap(), 0, This);\r
-}\r
-\r
-HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(\r
-  IEnumSTATSTG*     iface,\r
-  REFIID            riid,\r
-  void**            ppvObject)\r
-{\r
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;\r
-\r
-  /*\r
-   * Perform a sanity check on the parameters.\r
-   */\r
-  if (ppvObject==0)\r
-    return E_INVALIDARG;\r
-\r
-  /*\r
-   * Initialize the return parameter.\r
-   */\r
-  *ppvObject = 0;\r
-\r
-  /*\r
-   * Compare the riid with the interface IDs implemented by this object.\r
-   */\r
-  if (IsEqualGUID(&IID_IUnknown, riid) ||\r
-      IsEqualGUID(&IID_IStorage, riid))\r
-  {\r
-    *ppvObject = (IEnumSTATSTG*)This;\r
-    IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);\r
-    return S_OK;\r
-  }\r
-\r
-  return E_NOINTERFACE;\r
-}\r
-\r
-ULONG   WINAPI IEnumSTATSTGImpl_AddRef(\r
-  IEnumSTATSTG* iface)\r
-{\r
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;\r
-  return InterlockedIncrement(&This->ref);\r
-}\r
-\r
-ULONG   WINAPI IEnumSTATSTGImpl_Release(\r
-  IEnumSTATSTG* iface)\r
-{\r
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;\r
-\r
-  ULONG newRef;\r
-\r
-  newRef = InterlockedDecrement(&This->ref);\r
-\r
-  /*\r
-   * If the reference count goes down to 0, perform suicide.\r
-   */\r
-  if (newRef==0)\r
-  {\r
-    IEnumSTATSTGImpl_Destroy(This);\r
-  }\r
-\r
-  return newRef;\r
-}\r
-\r
-HRESULT WINAPI IEnumSTATSTGImpl_Next(\r
-  IEnumSTATSTG* iface,\r
-  ULONG             celt,\r
-  STATSTG*          rgelt,\r
-  ULONG*            pceltFetched)\r
-{\r
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;\r
-\r
-  StgProperty currentProperty;\r
-  STATSTG*    currentReturnStruct = rgelt;\r
-  ULONG       objectFetched       = 0;\r
-  ULONG      currentSearchNode;\r
-\r
-  /*\r
-   * Perform a sanity check on the parameters.\r
-   */\r
-  if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )\r
-    return E_INVALIDARG;\r
-\r
-  /*\r
-   * To avoid the special case, get another pointer to a ULONG value if\r
-   * the caller didn't supply one.\r
-   */\r
-  if (pceltFetched==0)\r
-    pceltFetched = &objectFetched;\r
-\r
-  /*\r
-   * Start the iteration, we will iterate until we hit the end of the\r
-   * linked list or until we hit the number of items to iterate through\r
-   */\r
-  *pceltFetched = 0;\r
-\r
-  /*\r
-   * Start with the node at the top of the stack.\r
-   */\r
-  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);\r
-\r
-  while ( ( *pceltFetched < celt) &&\r
-          ( currentSearchNode!=PROPERTY_NULL) )\r
-  {\r
-    /*\r
-     * Remove the top node from the stack\r
-     */\r
-    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);\r
-\r
-    /*\r
-     * Read the property from the storage.\r
-     */\r
-    StorageImpl_ReadProperty(This->parentStorage,\r
-      currentSearchNode,\r
-      &currentProperty);\r
-\r
-    /*\r
-     * Copy the information to the return buffer.\r
-     */\r
-    StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,\r
-      &currentProperty,\r
-      STATFLAG_DEFAULT);\r
-\r
-    /*\r
-     * Step to the next item in the iteration\r
-     */\r
-    (*pceltFetched)++;\r
-    currentReturnStruct++;\r
-\r
-    /*\r
-     * Push the next search node in the search stack.\r
-     */\r
-    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);\r
-\r
-    /*\r
-     * continue the iteration.\r
-     */\r
-    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);\r
-  }\r
-\r
-  if (*pceltFetched == celt)\r
-    return S_OK;\r
-\r
-  return S_FALSE;\r
-}\r
-\r
-\r
-HRESULT WINAPI IEnumSTATSTGImpl_Skip(\r
-  IEnumSTATSTG* iface,\r
-  ULONG             celt)\r
-{\r
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;\r
-\r
-  StgProperty currentProperty;\r
-  ULONG       objectFetched       = 0;\r
-  ULONG       currentSearchNode;\r
-\r
-  /*\r
-   * Start with the node at the top of the stack.\r
-   */\r
-  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);\r
-\r
-  while ( (objectFetched < celt) &&\r
-          (currentSearchNode!=PROPERTY_NULL) )\r
-  {\r
-    /*\r
-     * Remove the top node from the stack\r
-     */\r
-    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);\r
-\r
-    /*\r
-     * Read the property from the storage.\r
-     */\r
-    StorageImpl_ReadProperty(This->parentStorage,\r
-      currentSearchNode,\r
-      &currentProperty);\r
-\r
-    /*\r
-     * Step to the next item in the iteration\r
-     */\r
-    objectFetched++;\r
-\r
-    /*\r
-     * Push the next search node in the search stack.\r
-     */\r
-    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);\r
-\r
-    /*\r
-     * continue the iteration.\r
-     */\r
-    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);\r
-  }\r
-\r
-  if (objectFetched == celt)\r
-    return S_OK;\r
-\r
-  return S_FALSE;\r
-}\r
-\r
-HRESULT WINAPI IEnumSTATSTGImpl_Reset(\r
-  IEnumSTATSTG* iface)\r
-{\r
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;\r
-\r
-  StgProperty rootProperty;\r
-  BOOL      readSuccessful;\r
-\r
-  /*\r
-   * Re-initialize the search stack to an empty stack\r
-   */\r
-  This->stackSize = 0;\r
-\r
-  /*\r
-   * Read the root property from the storage.\r
-   */\r
-  readSuccessful = StorageImpl_ReadProperty(\r
-                    This->parentStorage,\r
-                    This->firstPropertyNode,\r
-                    &rootProperty);\r
-\r
-  if (readSuccessful)\r
-  {\r
-    assert(rootProperty.sizeOfNameString!=0);\r
-\r
-    /*\r
-     * Push the search node in the search stack.\r
-     */\r
-    IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);\r
-  }\r
-\r
-  return S_OK;\r
-}\r
-\r
-HRESULT WINAPI IEnumSTATSTGImpl_Clone(\r
-  IEnumSTATSTG* iface,\r
-  IEnumSTATSTG**    ppenum)\r
-{\r
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;\r
-\r
-  IEnumSTATSTGImpl* newClone;\r
-\r
-  /*\r
-   * Perform a sanity check on the parameters.\r
-   */\r
-  if (ppenum==0)\r
-    return E_INVALIDARG;\r
-\r
-  newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,\r
-               This->firstPropertyNode);\r
-\r
-\r
-  /*\r
-   * The new clone enumeration must point to the same current node as\r
-   * the ole one.\r
-   */\r
-  newClone->stackSize    = This->stackSize    ;\r
-  newClone->stackMaxSize = This->stackMaxSize ;\r
-  newClone->stackToVisit =\r
-    HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);\r
-\r
-  memcpy(\r
-    newClone->stackToVisit,\r
-    This->stackToVisit,\r
-    sizeof(ULONG) * newClone->stackSize);\r
-\r
-  *ppenum = (IEnumSTATSTG*)newClone;\r
-\r
-  /*\r
-   * Don't forget to nail down a reference to the clone before\r
-   * returning it.\r
-   */\r
-  IEnumSTATSTGImpl_AddRef(*ppenum);\r
-\r
-  return S_OK;\r
-}\r
-\r
-INT IEnumSTATSTGImpl_FindParentProperty(\r
-  IEnumSTATSTGImpl *This,\r
-  ULONG             childProperty,\r
-  StgProperty      *currentProperty,\r
-  ULONG            *thisNodeId)\r
-{\r
-  ULONG currentSearchNode;\r
-  ULONG foundNode;\r
-\r
-  /*\r
-   * To avoid the special case, get another pointer to a ULONG value if\r
-   * the caller didn't supply one.\r
-   */\r
-  if (thisNodeId==0)\r
-    thisNodeId = &foundNode;\r
-\r
-  /*\r
-   * Start with the node at the top of the stack.\r
-   */\r
-  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);\r
-\r
-\r
-  while (currentSearchNode!=PROPERTY_NULL)\r
-  {\r
-    /*\r
-     * Store the current node in the returned parameters\r
-     */\r
-    *thisNodeId = currentSearchNode;\r
-\r
-    /*\r
-     * Remove the top node from the stack\r
-     */\r
-    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);\r
-\r
-    /*\r
-     * Read the property from the storage.\r
-     */\r
-    StorageImpl_ReadProperty(\r
-      This->parentStorage,\r
-      currentSearchNode,\r
-      currentProperty);\r
-\r
-    if (currentProperty->previousProperty == childProperty)\r
-      return PROPERTY_RELATION_PREVIOUS;\r
-\r
-    else if (currentProperty->nextProperty == childProperty)\r
-      return PROPERTY_RELATION_NEXT;\r
-\r
-    else if (currentProperty->dirProperty == childProperty)\r
-      return PROPERTY_RELATION_DIR;\r
-\r
-    /*\r
-     * Push the next search node in the search stack.\r
-     */\r
-    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);\r
-\r
-    /*\r
-     * continue the iteration.\r
-     */\r
-    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);\r
-  }\r
-\r
-  return PROPERTY_NULL;\r
-}\r
-\r
-ULONG IEnumSTATSTGImpl_FindProperty(\r
-  IEnumSTATSTGImpl* This,\r
-  const OLECHAR*  lpszPropName,\r
-  StgProperty*      currentProperty)\r
-{\r
-  ULONG currentSearchNode;\r
-\r
-  /*\r
-   * Start with the node at the top of the stack.\r
-   */\r
-  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);\r
-\r
-  while (currentSearchNode!=PROPERTY_NULL)\r
-  {\r
-    /*\r
-     * Remove the top node from the stack\r
-     */\r
-    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);\r
-\r
-    /*\r
-     * Read the property from the storage.\r
-     */\r
-    StorageImpl_ReadProperty(This->parentStorage,\r
-      currentSearchNode,\r
-      currentProperty);\r
-\r
-    if ( propertyNameCmp(\r
-          (const OLECHAR*)currentProperty->name,\r
-          (const OLECHAR*)lpszPropName) == 0)\r
-      return currentSearchNode;\r
-\r
-    /*\r
-     * Push the next search node in the search stack.\r
-     */\r
-    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);\r
-\r
-    /*\r
-     * continue the iteration.\r
-     */\r
-    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);\r
-  }\r
-\r
-  return PROPERTY_NULL;\r
-}\r
-\r
-void IEnumSTATSTGImpl_PushSearchNode(\r
-  IEnumSTATSTGImpl* This,\r
-  ULONG             nodeToPush)\r
-{\r
-  StgProperty rootProperty;\r
-  BOOL      readSuccessful;\r
-\r
-  /*\r
-   * First, make sure we're not trying to push an unexisting node.\r
-   */\r
-  if (nodeToPush==PROPERTY_NULL)\r
-    return;\r
-\r
-  /*\r
-   * First push the node to the stack\r
-   */\r
-  if (This->stackSize == This->stackMaxSize)\r
-  {\r
-    This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;\r
-\r
-    This->stackToVisit = HeapReAlloc(\r
-                           GetProcessHeap(),\r
-                           0,\r
-                           This->stackToVisit,\r
-                           sizeof(ULONG) * This->stackMaxSize);\r
-  }\r
-\r
-  This->stackToVisit[This->stackSize] = nodeToPush;\r
-  This->stackSize++;\r
-\r
-  /*\r
-   * Read the root property from the storage.\r
-   */\r
-  readSuccessful = StorageImpl_ReadProperty(\r
-                    This->parentStorage,\r
-                    nodeToPush,\r
-                    &rootProperty);\r
-\r
-  if (readSuccessful)\r
-  {\r
-    assert(rootProperty.sizeOfNameString!=0);\r
-\r
-    /*\r
-     * Push the previous search node in the search stack.\r
-     */\r
-    IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);\r
-  }\r
-}\r
-\r
-ULONG IEnumSTATSTGImpl_PopSearchNode(\r
-  IEnumSTATSTGImpl* This,\r
-  BOOL            remove)\r
-{\r
-  ULONG topNode;\r
-\r
-  if (This->stackSize == 0)\r
-    return PROPERTY_NULL;\r
-\r
-  topNode = This->stackToVisit[This->stackSize-1];\r
-\r
-  if (remove)\r
-    This->stackSize--;\r
-\r
-  return topNode;\r
-}\r
-\r
-/*\r
- * Virtual function table for the IEnumSTATSTGImpl class.\r
- */\r
-static IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =\r
-{\r
-    IEnumSTATSTGImpl_QueryInterface,\r
-    IEnumSTATSTGImpl_AddRef,\r
-    IEnumSTATSTGImpl_Release,\r
-    IEnumSTATSTGImpl_Next,\r
-    IEnumSTATSTGImpl_Skip,\r
-    IEnumSTATSTGImpl_Reset,\r
-    IEnumSTATSTGImpl_Clone\r
-};\r
-\r
-/******************************************************************************\r
-** IEnumSTATSTGImpl implementation\r
-*/\r
-\r
-IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(\r
-  StorageImpl* parentStorage,\r
-  ULONG          firstPropertyNode)\r
-{\r
-  IEnumSTATSTGImpl* newEnumeration;\r
-\r
-  newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));\r
-\r
-  if (newEnumeration!=0)\r
-  {\r
-    /*\r
-     * Set-up the virtual function table and reference count.\r
-     */\r
-    newEnumeration->lpVtbl    = &IEnumSTATSTGImpl_Vtbl;\r
-    newEnumeration->ref       = 0;\r
-\r
-    /*\r
-     * We want to nail-down the reference to the storage in case the\r
-     * enumeration out-lives the storage in the client application.\r
-     */\r
-    newEnumeration->parentStorage = parentStorage;\r
-    IStorage_AddRef((IStorage*)newEnumeration->parentStorage);\r
-\r
-    newEnumeration->firstPropertyNode   = firstPropertyNode;\r
-\r
-    /*\r
-     * Initialize the search stack\r
-     */\r
-    newEnumeration->stackSize    = 0;\r
-    newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;\r
-    newEnumeration->stackToVisit =\r
-      HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);\r
-\r
-    /*\r
-     * Make sure the current node of the iterator is the first one.\r
-     */\r
-    IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);\r
-  }\r
-\r
-  return newEnumeration;\r
-}\r
-\r
-/*\r
- * Virtual function table for the Storage32InternalImpl class.\r
- */\r
-static IStorageVtbl Storage32InternalImpl_Vtbl =\r
-{\r
-    StorageBaseImpl_QueryInterface,\r
-    StorageBaseImpl_AddRef,\r
-    StorageBaseImpl_Release,\r
-    StorageBaseImpl_CreateStream,\r
-    StorageBaseImpl_OpenStream,\r
-    StorageImpl_CreateStorage,\r
-    StorageBaseImpl_OpenStorage,\r
-    StorageImpl_CopyTo,\r
-    StorageImpl_MoveElementTo,\r
-    StorageInternalImpl_Commit,\r
-    StorageInternalImpl_Revert,\r
-    StorageBaseImpl_EnumElements,\r
-    StorageImpl_DestroyElement,\r
-    StorageBaseImpl_RenameElement,\r
-    StorageImpl_SetElementTimes,\r
-    StorageBaseImpl_SetClass,\r
-    StorageImpl_SetStateBits,\r
-    StorageBaseImpl_Stat\r
-};\r
-\r
-/******************************************************************************\r
-** Storage32InternalImpl implementation\r
-*/\r
-\r
-StorageInternalImpl* StorageInternalImpl_Construct(\r
-  StorageImpl* ancestorStorage,\r
-  DWORD        openFlags,\r
-  ULONG        rootPropertyIndex)\r
-{\r
-  StorageInternalImpl* newStorage;\r
-\r
-  /*\r
-   * Allocate space for the new storage object\r
-   */\r
-  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));\r
-\r
-  if (newStorage!=0)\r
-  {\r
-    memset(newStorage, 0, sizeof(StorageInternalImpl));\r
-\r
-    /*\r
-     * Initialize the virtual function table.\r
-     */\r
-    newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;\r
-    newStorage->base.v_destructor = &StorageInternalImpl_Destroy;\r
-    newStorage->base.openFlags = openFlags;\r
-\r
-    /*\r
-     * Keep the ancestor storage pointer and nail a reference to it.\r
-     */\r
-    newStorage->base.ancestorStorage = ancestorStorage;\r
-    StorageBaseImpl_AddRef((IStorage*)(newStorage->base.ancestorStorage));\r
-\r
-    /*\r
-     * Keep the index of the root property set for this storage,\r
-     */\r
-    newStorage->base.rootPropertySetIndex = rootPropertyIndex;\r
-\r
-    return newStorage;\r
-  }\r
-\r
-  return 0;\r
-}\r
-\r
-/******************************************************************************\r
-** StorageUtl implementation\r
-*/\r
-\r
-void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value)\r
-{\r
-  WORD tmp;\r
-\r
-  memcpy(&tmp, buffer+offset, sizeof(WORD));\r
-  *value = le16toh(tmp);\r
-}\r
-\r
-void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value)\r
-{\r
-  value = htole16(value);\r
-  memcpy(buffer+offset, &value, sizeof(WORD));\r
-}\r
-\r
-void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)\r
-{\r
-  DWORD tmp;\r
-\r
-  memcpy(&tmp, buffer+offset, sizeof(DWORD));\r
-  *value = le32toh(tmp);\r
-}\r
-\r
-void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)\r
-{\r
-  value = htole32(value);\r
-  memcpy(buffer+offset, &value, sizeof(DWORD));\r
-}\r
-\r
-void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,\r
- ULARGE_INTEGER* value)\r
-{\r
-#ifdef WORDS_BIGENDIAN\r
-    ULARGE_INTEGER tmp;\r
-\r
-    memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));\r
-    value->u.LowPart = htole32(tmp.u.HighPart);\r
-    value->u.HighPart = htole32(tmp.u.LowPart);\r
-#else\r
-    memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER));\r
-#endif\r
-}\r
-\r
-void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,\r
- const ULARGE_INTEGER *value)\r
-{\r
-#ifdef WORDS_BIGENDIAN\r
-    ULARGE_INTEGER tmp;\r
-\r
-    tmp.u.LowPart = htole32(value->u.HighPart);\r
-    tmp.u.HighPart = htole32(value->u.LowPart);\r
-    memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER));\r
-#else\r
-    memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER));\r
-#endif\r
-}\r
-\r
-void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value)\r
-{\r
-  StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));\r
-  StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));\r
-  StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));\r
-\r
-  memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));\r
-}\r
-\r
-void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value)\r
-{\r
-  StorageUtl_WriteDWord(buffer, offset,   value->Data1);\r
-  StorageUtl_WriteWord(buffer,  offset+4, value->Data2);\r
-  StorageUtl_WriteWord(buffer,  offset+6, value->Data3);\r
-\r
-  memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));\r
-}\r
-\r
-void StorageUtl_CopyPropertyToSTATSTG(\r
-  STATSTG*     destination,\r
-  StgProperty* source,\r
-  int          statFlags)\r
-{\r
-  /*\r
-   * The copy of the string occurs only when the flag is not set\r
-   */\r
-  if( ((statFlags & STATFLAG_NONAME) != 0) || \r
-       (source->name == NULL) || \r
-       (source->name[0] == 0) )\r
-  {\r
-    destination->pwcsName = 0;\r
-  }\r
-  else\r
-  {\r
-    destination->pwcsName =\r
-      CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));\r
-\r
-    strcpyW((LPWSTR)destination->pwcsName, source->name);\r
-  }\r
-\r
-  switch (source->propertyType)\r
-  {\r
-    case PROPTYPE_STORAGE:\r
-    case PROPTYPE_ROOT:\r
-      destination->type = STGTY_STORAGE;\r
-      break;\r
-    case PROPTYPE_STREAM:\r
-      destination->type = STGTY_STREAM;\r
-      break;\r
-    default:\r
-      destination->type = STGTY_STREAM;\r
-      break;\r
-  }\r
-\r
-  destination->cbSize            = source->size;\r
-/*\r
-  currentReturnStruct->mtime     = {0}; TODO\r
-  currentReturnStruct->ctime     = {0};\r
-  currentReturnStruct->atime     = {0};\r
-*/\r
-  destination->grfMode           = 0;\r
-  destination->grfLocksSupported = 0;\r
-  destination->clsid             = source->propertyUniqueID;\r
-  destination->grfStateBits      = 0;\r
-  destination->reserved          = 0;\r
-}\r
-\r
-/******************************************************************************\r
-** BlockChainStream implementation\r
-*/\r
-\r
-BlockChainStream* BlockChainStream_Construct(\r
-  StorageImpl* parentStorage,\r
-  ULONG*         headOfStreamPlaceHolder,\r
-  ULONG          propertyIndex)\r
-{\r
-  BlockChainStream* newStream;\r
-  ULONG blockIndex;\r
-\r
-  newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));\r
-\r
-  newStream->parentStorage           = parentStorage;\r
-  newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;\r
-  newStream->ownerPropertyIndex      = propertyIndex;\r
-  newStream->lastBlockNoInSequence   = 0xFFFFFFFF;\r
-  newStream->tailIndex               = BLOCK_END_OF_CHAIN;\r
-  newStream->numBlocks               = 0;\r
-\r
-  blockIndex = BlockChainStream_GetHeadOfChain(newStream);\r
-\r
-  while (blockIndex != BLOCK_END_OF_CHAIN)\r
-  {\r
-    newStream->numBlocks++;\r
-    newStream->tailIndex = blockIndex;\r
-\r
-    if(FAILED(StorageImpl_GetNextBlockInChain(\r
-             parentStorage,\r
-             blockIndex,\r
-             &blockIndex)))\r
-    {\r
-      HeapFree(GetProcessHeap(), 0, newStream);\r
-      return NULL;\r
-    }\r
-  }\r
-\r
-  return newStream;\r
-}\r
-\r
-void BlockChainStream_Destroy(BlockChainStream* This)\r
-{\r
-  HeapFree(GetProcessHeap(), 0, This);\r
-}\r
-\r
-/******************************************************************************\r
- *      BlockChainStream_GetHeadOfChain\r
- *\r
- * Returns the head of this stream chain.\r
- * Some special chains don't have properties, their heads are kept in\r
- * This->headOfStreamPlaceHolder.\r
- *\r
- */\r
-ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)\r
-{\r
-  StgProperty chainProperty;\r
-  BOOL      readSuccessful;\r
-\r
-  if (This->headOfStreamPlaceHolder != 0)\r
-    return *(This->headOfStreamPlaceHolder);\r
-\r
-  if (This->ownerPropertyIndex != PROPERTY_NULL)\r
-  {\r
-    readSuccessful = StorageImpl_ReadProperty(\r
-                      This->parentStorage,\r
-                      This->ownerPropertyIndex,\r
-                      &chainProperty);\r
-\r
-    if (readSuccessful)\r
-    {\r
-      return chainProperty.startingBlock;\r
-    }\r
-  }\r
-\r
-  return BLOCK_END_OF_CHAIN;\r
-}\r
-\r
-/******************************************************************************\r
- *       BlockChainStream_GetCount\r
- *\r
- * Returns the number of blocks that comprises this chain.\r
- * This is not the size of the stream as the last block may not be full!\r
- *\r
- */\r
-ULONG BlockChainStream_GetCount(BlockChainStream* This)\r
-{\r
-  ULONG blockIndex;\r
-  ULONG count = 0;\r
-\r
-  blockIndex = BlockChainStream_GetHeadOfChain(This);\r
-\r
-  while (blockIndex != BLOCK_END_OF_CHAIN)\r
-  {\r
-    count++;\r
-\r
-    if(FAILED(StorageImpl_GetNextBlockInChain(\r
-                   This->parentStorage,\r
-                   blockIndex,\r
-                  &blockIndex)))\r
-      return 0;\r
-  }\r
-\r
-  return count;\r
-}\r
-\r
-/******************************************************************************\r
- *      BlockChainStream_ReadAt\r
- *\r
- * Reads a specified number of bytes from this chain at the specified offset.\r
- * bytesRead may be NULL.\r
- * Failure will be returned if the specified number of bytes has not been read.\r
- */\r
-BOOL BlockChainStream_ReadAt(BlockChainStream* This,\r
-  ULARGE_INTEGER offset,\r
-  ULONG          size,\r
-  void*          buffer,\r
-  ULONG*         bytesRead)\r
-{\r
-  ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;\r
-  ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;\r
-  ULONG bytesToReadInBuffer;\r
-  ULONG blockIndex;\r
-  BYTE* bufferWalker;\r
-  BYTE* bigBlockBuffer;\r
-\r
-  /*\r
-   * Find the first block in the stream that contains part of the buffer.\r
-   */\r
-  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||\r
-       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||\r
-       (blockNoInSequence < This->lastBlockNoInSequence) )\r
-  {\r
-    blockIndex = BlockChainStream_GetHeadOfChain(This);\r
-    This->lastBlockNoInSequence = blockNoInSequence;\r
-  }\r
-  else\r
-  {\r
-    ULONG temp = blockNoInSequence;\r
-\r
-    blockIndex = This->lastBlockNoInSequenceIndex;\r
-    blockNoInSequence -= This->lastBlockNoInSequence;\r
-    This->lastBlockNoInSequence = temp;\r
-  }\r
-\r
-  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))\r
-  {\r
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))\r
-      return FALSE;\r
-    blockNoInSequence--;\r
-  }\r
-\r
-  This->lastBlockNoInSequenceIndex = blockIndex;\r
-\r
-  /*\r
-   * Start reading the buffer.\r
-   */\r
-  *bytesRead   = 0;\r
-  bufferWalker = buffer;\r
-\r
-  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )\r
-  {\r
-    /*\r
-     * Calculate how many bytes we can copy from this big block.\r
-     */\r
-    bytesToReadInBuffer =\r
-      min(This->parentStorage->bigBlockSize - offsetInBlock, size);\r
-\r
-    /*\r
-     * Copy those bytes to the buffer\r
-     */\r
-    bigBlockBuffer =\r
-      StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);\r
-\r
-    memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);\r
-\r
-    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);\r
-\r
-    /*\r
-     * Step to the next big block.\r
-     */\r
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))\r
-      return FALSE;\r
-\r
-    bufferWalker += bytesToReadInBuffer;\r
-    size         -= bytesToReadInBuffer;\r
-    *bytesRead   += bytesToReadInBuffer;\r
-    offsetInBlock = 0;  /* There is no offset on the next block */\r
-\r
-  }\r
-\r
-  return (size == 0);\r
-}\r
-\r
-/******************************************************************************\r
- *      BlockChainStream_WriteAt\r
- *\r
- * Writes the specified number of bytes to this chain at the specified offset.\r
- * bytesWritten may be NULL.\r
- * Will fail if not all specified number of bytes have been written.\r
- */\r
-BOOL BlockChainStream_WriteAt(BlockChainStream* This,\r
-  ULARGE_INTEGER    offset,\r
-  ULONG             size,\r
-  const void*       buffer,\r
-  ULONG*            bytesWritten)\r
-{\r
-  ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;\r
-  ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;\r
-  ULONG bytesToWrite;\r
-  ULONG blockIndex;\r
-  const BYTE* bufferWalker;\r
-  BYTE* bigBlockBuffer;\r
-\r
-  /*\r
-   * Find the first block in the stream that contains part of the buffer.\r
-   */\r
-  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||\r
-       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||\r
-       (blockNoInSequence < This->lastBlockNoInSequence) )\r
-  {\r
-    blockIndex = BlockChainStream_GetHeadOfChain(This);\r
-    This->lastBlockNoInSequence = blockNoInSequence;\r
-  }\r
-  else\r
-  {\r
-    ULONG temp = blockNoInSequence;\r
-\r
-    blockIndex = This->lastBlockNoInSequenceIndex;\r
-    blockNoInSequence -= This->lastBlockNoInSequence;\r
-    This->lastBlockNoInSequence = temp;\r
-  }\r
-\r
-  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))\r
-  {\r
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,\r
-                                             &blockIndex)))\r
-      return FALSE;\r
-    blockNoInSequence--;\r
-  }\r
-\r
-  This->lastBlockNoInSequenceIndex = blockIndex;\r
-\r
-  /*\r
-   * Here, I'm casting away the constness on the buffer variable\r
-   * This is OK since we don't intend to modify that buffer.\r
-   */\r
-  *bytesWritten   = 0;\r
-  bufferWalker = (const BYTE*)buffer;\r
-\r
-  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )\r
-  {\r
-    /*\r
-     * Calculate how many bytes we can copy from this big block.\r
-     */\r
-    bytesToWrite =\r
-      min(This->parentStorage->bigBlockSize - offsetInBlock, size);\r
-\r
-    /*\r
-     * Copy those bytes to the buffer\r
-     */\r
-    bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);\r
-\r
-    memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);\r
-\r
-    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);\r
-\r
-    /*\r
-     * Step to the next big block.\r
-     */\r
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,\r
-                                             &blockIndex)))\r
-      return FALSE;\r
-    bufferWalker  += bytesToWrite;\r
-    size          -= bytesToWrite;\r
-    *bytesWritten += bytesToWrite;\r
-    offsetInBlock  = 0;      /* There is no offset on the next block */\r
-  }\r
-\r
-  return (size == 0);\r
-}\r
-\r
-/******************************************************************************\r
- *      BlockChainStream_Shrink\r
- *\r
- * Shrinks this chain in the big block depot.\r
- */\r
-BOOL BlockChainStream_Shrink(BlockChainStream* This,\r
-                               ULARGE_INTEGER    newSize)\r
-{\r
-  ULONG blockIndex, extraBlock;\r
-  ULONG numBlocks;\r
-  ULONG count = 1;\r
-\r
-  /*\r
-   * Reset the last accessed block cache.\r
-   */\r
-  This->lastBlockNoInSequence = 0xFFFFFFFF;\r
-  This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;\r
-\r
-  /*\r
-   * Figure out how many blocks are needed to contain the new size\r
-   */\r
-  numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;\r
-\r
-  if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)\r
-    numBlocks++;\r
-\r
-  blockIndex = BlockChainStream_GetHeadOfChain(This);\r
-\r
-  /*\r
-   * Go to the new end of chain\r
-   */\r
-  while (count < numBlocks)\r
-  {\r
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,\r
-                                             &blockIndex)))\r
-      return FALSE;\r
-    count++;\r
-  }\r
-\r
-  /* Get the next block before marking the new end */\r
-  if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,\r
-                                           &extraBlock)))\r
-    return FALSE;\r
-\r
-  /* Mark the new end of chain */\r
-  StorageImpl_SetNextBlockInChain(\r
-    This->parentStorage,\r
-    blockIndex,\r
-    BLOCK_END_OF_CHAIN);\r
-\r
-  This->tailIndex = blockIndex;\r
-  This->numBlocks = numBlocks;\r
-\r
-  /*\r
-   * Mark the extra blocks as free\r
-   */\r
-  while (extraBlock != BLOCK_END_OF_CHAIN)\r
-  {\r
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock,\r
-                                             &blockIndex)))\r
-      return FALSE;\r
-    StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);\r
-    extraBlock = blockIndex;\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *      BlockChainStream_Enlarge\r
- *\r
- * Grows this chain in the big block depot.\r
- */\r
-BOOL BlockChainStream_Enlarge(BlockChainStream* This,\r
-                                ULARGE_INTEGER    newSize)\r
-{\r
-  ULONG blockIndex, currentBlock;\r
-  ULONG newNumBlocks;\r
-  ULONG oldNumBlocks = 0;\r
-\r
-  blockIndex = BlockChainStream_GetHeadOfChain(This);\r
-\r
-  /*\r
-   * Empty chain. Create the head.\r
-   */\r
-  if (blockIndex == BLOCK_END_OF_CHAIN)\r
-  {\r
-    blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);\r
-    StorageImpl_SetNextBlockInChain(This->parentStorage,\r
-                                      blockIndex,\r
-                                      BLOCK_END_OF_CHAIN);\r
-\r
-    if (This->headOfStreamPlaceHolder != 0)\r
-    {\r
-      *(This->headOfStreamPlaceHolder) = blockIndex;\r
-    }\r
-    else\r
-    {\r
-      StgProperty chainProp;\r
-      assert(This->ownerPropertyIndex != PROPERTY_NULL);\r
-\r
-      StorageImpl_ReadProperty(\r
-        This->parentStorage,\r
-        This->ownerPropertyIndex,\r
-        &chainProp);\r
-\r
-      chainProp.startingBlock = blockIndex;\r
-\r
-      StorageImpl_WriteProperty(\r
-        This->parentStorage,\r
-        This->ownerPropertyIndex,\r
-        &chainProp);\r
-    }\r
-\r
-    This->tailIndex = blockIndex;\r
-    This->numBlocks = 1;\r
-  }\r
-\r
-  /*\r
-   * Figure out how many blocks are needed to contain this stream\r
-   */\r
-  newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;\r
-\r
-  if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)\r
-    newNumBlocks++;\r
-\r
-  /*\r
-   * Go to the current end of chain\r
-   */\r
-  if (This->tailIndex == BLOCK_END_OF_CHAIN)\r
-  {\r
-    currentBlock = blockIndex;\r
-\r
-    while (blockIndex != BLOCK_END_OF_CHAIN)\r
-    {\r
-      This->numBlocks++;\r
-      currentBlock = blockIndex;\r
-\r
-      if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock,\r
-                                               &blockIndex)))\r
-       return FALSE;\r
-    }\r
-\r
-    This->tailIndex = currentBlock;\r
-  }\r
-\r
-  currentBlock = This->tailIndex;\r
-  oldNumBlocks = This->numBlocks;\r
-\r
-  /*\r
-   * Add new blocks to the chain\r
-   */\r
-  if (oldNumBlocks < newNumBlocks)\r
-  {\r
-    while (oldNumBlocks < newNumBlocks)\r
-    {\r
-      blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);\r
-\r
-      StorageImpl_SetNextBlockInChain(\r
-       This->parentStorage,\r
-       currentBlock,\r
-       blockIndex);\r
-\r
-      StorageImpl_SetNextBlockInChain(\r
-        This->parentStorage,\r
-       blockIndex,\r
-       BLOCK_END_OF_CHAIN);\r
-\r
-      currentBlock = blockIndex;\r
-      oldNumBlocks++;\r
-    }\r
-\r
-    This->tailIndex = blockIndex;\r
-    This->numBlocks = newNumBlocks;\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *      BlockChainStream_SetSize\r
- *\r
- * Sets the size of this stream. The big block depot will be updated.\r
- * The file will grow if we grow the chain.\r
- *\r
- * TODO: Free the actual blocks in the file when we shrink the chain.\r
- *       Currently, the blocks are still in the file. So the file size\r
- *       doesn't shrink even if we shrink streams.\r
- */\r
-BOOL BlockChainStream_SetSize(\r
-  BlockChainStream* This,\r
-  ULARGE_INTEGER    newSize)\r
-{\r
-  ULARGE_INTEGER size = BlockChainStream_GetSize(This);\r
-\r
-  if (newSize.u.LowPart == size.u.LowPart)\r
-    return TRUE;\r
-\r
-  if (newSize.u.LowPart < size.u.LowPart)\r
-  {\r
-    BlockChainStream_Shrink(This, newSize);\r
-  }\r
-  else\r
-  {\r
-    ULARGE_INTEGER fileSize =\r
-      BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);\r
-\r
-    ULONG diff = newSize.u.LowPart - size.u.LowPart;\r
-\r
-    /*\r
-     * Make sure the file stays a multiple of blocksize\r
-     */\r
-    if ((diff % This->parentStorage->bigBlockSize) != 0)\r
-      diff += (This->parentStorage->bigBlockSize -\r
-                (diff % This->parentStorage->bigBlockSize) );\r
-\r
-    fileSize.u.LowPart += diff;\r
-    BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);\r
-\r
-    BlockChainStream_Enlarge(This, newSize);\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *      BlockChainStream_GetSize\r
- *\r
- * Returns the size of this chain.\r
- * Will return the block count if this chain doesn't have a property.\r
- */\r
-ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)\r
-{\r
-  StgProperty chainProperty;\r
-\r
-  if(This->headOfStreamPlaceHolder == NULL)\r
-  {\r
-    /*\r
-     * This chain is a data stream read the property and return\r
-     * the appropriate size\r
-     */\r
-    StorageImpl_ReadProperty(\r
-      This->parentStorage,\r
-      This->ownerPropertyIndex,\r
-      &chainProperty);\r
-\r
-    return chainProperty.size;\r
-  }\r
-  else\r
-  {\r
-    /*\r
-     * this chain is a chain that does not have a property, figure out the\r
-     * size by making the product number of used blocks times the\r
-     * size of them\r
-     */\r
-    ULARGE_INTEGER result;\r
-    result.u.HighPart = 0;\r
-\r
-    result.u.LowPart  =\r
-      BlockChainStream_GetCount(This) *\r
-      This->parentStorage->bigBlockSize;\r
-\r
-    return result;\r
-  }\r
-}\r
-\r
-/******************************************************************************\r
-** SmallBlockChainStream implementation\r
-*/\r
-\r
-SmallBlockChainStream* SmallBlockChainStream_Construct(\r
-  StorageImpl* parentStorage,\r
-  ULONG          propertyIndex)\r
-{\r
-  SmallBlockChainStream* newStream;\r
-\r
-  newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));\r
-\r
-  newStream->parentStorage      = parentStorage;\r
-  newStream->ownerPropertyIndex = propertyIndex;\r
-\r
-  return newStream;\r
-}\r
-\r
-void SmallBlockChainStream_Destroy(\r
-  SmallBlockChainStream* This)\r
-{\r
-  HeapFree(GetProcessHeap(), 0, This);\r
-}\r
-\r
-/******************************************************************************\r
- *      SmallBlockChainStream_GetHeadOfChain\r
- *\r
- * Returns the head of this chain of small blocks.\r
- */\r
-ULONG SmallBlockChainStream_GetHeadOfChain(\r
-  SmallBlockChainStream* This)\r
-{\r
-  StgProperty chainProperty;\r
-  BOOL      readSuccessful;\r
-\r
-  if (This->ownerPropertyIndex)\r
-  {\r
-    readSuccessful = StorageImpl_ReadProperty(\r
-                      This->parentStorage,\r
-                      This->ownerPropertyIndex,\r
-                      &chainProperty);\r
-\r
-    if (readSuccessful)\r
-    {\r
-      return chainProperty.startingBlock;\r
-    }\r
-\r
-  }\r
-\r
-  return BLOCK_END_OF_CHAIN;\r
-}\r
-\r
-/******************************************************************************\r
- *      SmallBlockChainStream_GetNextBlockInChain\r
- *\r
- * Returns the index of the next small block in this chain.\r
- *\r
- * Return Values:\r
- *    - BLOCK_END_OF_CHAIN: end of this chain\r
- *    - BLOCK_UNUSED: small block 'blockIndex' is free\r
- */\r
-HRESULT SmallBlockChainStream_GetNextBlockInChain(\r
-  SmallBlockChainStream* This,\r
-  ULONG                  blockIndex,\r
-  ULONG*                 nextBlockInChain)\r
-{\r
-  ULARGE_INTEGER offsetOfBlockInDepot;\r
-  DWORD  buffer;\r
-  ULONG  bytesRead;\r
-  BOOL success;\r
-\r
-  *nextBlockInChain = BLOCK_END_OF_CHAIN;\r
-\r
-  offsetOfBlockInDepot.u.HighPart = 0;\r
-  offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);\r
-\r
-  /*\r
-   * Read those bytes in the buffer from the small block file.\r
-   */\r
-  success = BlockChainStream_ReadAt(\r
-              This->parentStorage->smallBlockDepotChain,\r
-              offsetOfBlockInDepot,\r
-              sizeof(DWORD),\r
-              &buffer,\r
-              &bytesRead);\r
-\r
-  if (success)\r
-  {\r
-    StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);\r
-    return S_OK;\r
-  }\r
-\r
-  return STG_E_READFAULT;\r
-}\r
-\r
-/******************************************************************************\r
- *       SmallBlockChainStream_SetNextBlockInChain\r
- *\r
- * Writes the index of the next block of the specified block in the small\r
- * block depot.\r
- * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.\r
- * To flag a block as free use BLOCK_UNUSED as nextBlock.\r
- */\r
-void SmallBlockChainStream_SetNextBlockInChain(\r
-  SmallBlockChainStream* This,\r
-  ULONG                  blockIndex,\r
-  ULONG                  nextBlock)\r
-{\r
-  ULARGE_INTEGER offsetOfBlockInDepot;\r
-  DWORD  buffer;\r
-  ULONG  bytesWritten;\r
-\r
-  offsetOfBlockInDepot.u.HighPart = 0;\r
-  offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);\r
-\r
-  StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);\r
-\r
-  /*\r
-   * Read those bytes in the buffer from the small block file.\r
-   */\r
-  BlockChainStream_WriteAt(\r
-    This->parentStorage->smallBlockDepotChain,\r
-    offsetOfBlockInDepot,\r
-    sizeof(DWORD),\r
-    &buffer,\r
-    &bytesWritten);\r
-}\r
-\r
-/******************************************************************************\r
- *      SmallBlockChainStream_FreeBlock\r
- *\r
- * Flag small block 'blockIndex' as free in the small block depot.\r
- */\r
-void SmallBlockChainStream_FreeBlock(\r
-  SmallBlockChainStream* This,\r
-  ULONG                  blockIndex)\r
-{\r
-  SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);\r
-}\r
-\r
-/******************************************************************************\r
- *      SmallBlockChainStream_GetNextFreeBlock\r
- *\r
- * Returns the index of a free small block. The small block depot will be\r
- * enlarged if necessary. The small block chain will also be enlarged if\r
- * necessary.\r
- */\r
-ULONG SmallBlockChainStream_GetNextFreeBlock(\r
-  SmallBlockChainStream* This)\r
-{\r
-  ULARGE_INTEGER offsetOfBlockInDepot;\r
-  DWORD buffer;\r
-  ULONG bytesRead;\r
-  ULONG blockIndex = 0;\r
-  ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;\r
-  BOOL success = TRUE;\r
-  ULONG smallBlocksPerBigBlock;\r
-\r
-  offsetOfBlockInDepot.u.HighPart = 0;\r
-\r
-  /*\r
-   * Scan the small block depot for a free block\r
-   */\r
-  while (nextBlockIndex != BLOCK_UNUSED)\r
-  {\r
-    offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);\r
-\r
-    success = BlockChainStream_ReadAt(\r
-                This->parentStorage->smallBlockDepotChain,\r
-                offsetOfBlockInDepot,\r
-                sizeof(DWORD),\r
-                &buffer,\r
-                &bytesRead);\r
-\r
-    /*\r
-     * If we run out of space for the small block depot, enlarge it\r
-     */\r
-    if (success)\r
-    {\r
-      StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);\r
-\r
-      if (nextBlockIndex != BLOCK_UNUSED)\r
-        blockIndex++;\r
-    }\r
-    else\r
-    {\r
-      ULONG count =\r
-        BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);\r
-\r
-      ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;\r
-      ULONG nextBlock, newsbdIndex;\r
-      BYTE* smallBlockDepot;\r
-\r
-      nextBlock = sbdIndex;\r
-      while (nextBlock != BLOCK_END_OF_CHAIN)\r
-      {\r
-        sbdIndex = nextBlock;\r
-       StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock);\r
-      }\r
-\r
-      newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);\r
-      if (sbdIndex != BLOCK_END_OF_CHAIN)\r
-        StorageImpl_SetNextBlockInChain(\r
-          This->parentStorage,\r
-          sbdIndex,\r
-          newsbdIndex);\r
-\r
-      StorageImpl_SetNextBlockInChain(\r
-        This->parentStorage,\r
-        newsbdIndex,\r
-        BLOCK_END_OF_CHAIN);\r
-\r
-      /*\r
-       * Initialize all the small blocks to free\r
-       */\r
-      smallBlockDepot =\r
-        StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);\r
-\r
-      memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);\r
-      StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);\r
-\r
-      if (count == 0)\r
-      {\r
-        /*\r
-         * We have just created the small block depot.\r
-         */\r
-        StgProperty rootProp;\r
-        ULONG sbStartIndex;\r
-\r
-        /*\r
-         * Save it in the header\r
-         */\r
-        This->parentStorage->smallBlockDepotStart = newsbdIndex;\r
-        StorageImpl_SaveFileHeader(This->parentStorage);\r
-\r
-        /*\r
-         * And allocate the first big block that will contain small blocks\r
-         */\r
-        sbStartIndex =\r
-          StorageImpl_GetNextFreeBigBlock(This->parentStorage);\r
-\r
-        StorageImpl_SetNextBlockInChain(\r
-          This->parentStorage,\r
-          sbStartIndex,\r
-          BLOCK_END_OF_CHAIN);\r
-\r
-        StorageImpl_ReadProperty(\r
-          This->parentStorage,\r
-          This->parentStorage->base.rootPropertySetIndex,\r
-          &rootProp);\r
-\r
-        rootProp.startingBlock = sbStartIndex;\r
-        rootProp.size.u.HighPart = 0;\r
-        rootProp.size.u.LowPart  = This->parentStorage->bigBlockSize;\r
-\r
-        StorageImpl_WriteProperty(\r
-          This->parentStorage,\r
-          This->parentStorage->base.rootPropertySetIndex,\r
-          &rootProp);\r
-      }\r
-    }\r
-  }\r
-\r
-  smallBlocksPerBigBlock =\r
-    This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;\r
-\r
-  /*\r
-   * Verify if we have to allocate big blocks to contain small blocks\r
-   */\r
-  if (blockIndex % smallBlocksPerBigBlock == 0)\r
-  {\r
-    StgProperty rootProp;\r
-    ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;\r
-\r
-    StorageImpl_ReadProperty(\r
-      This->parentStorage,\r
-      This->parentStorage->base.rootPropertySetIndex,\r
-      &rootProp);\r
-\r
-    if (rootProp.size.u.LowPart <\r
-       (blocksRequired * This->parentStorage->bigBlockSize))\r
-    {\r
-      rootProp.size.u.LowPart += This->parentStorage->bigBlockSize;\r
-\r
-      BlockChainStream_SetSize(\r
-        This->parentStorage->smallBlockRootChain,\r
-        rootProp.size);\r
-\r
-      StorageImpl_WriteProperty(\r
-        This->parentStorage,\r
-        This->parentStorage->base.rootPropertySetIndex,\r
-        &rootProp);\r
-    }\r
-  }\r
-\r
-  return blockIndex;\r
-}\r
-\r
-/******************************************************************************\r
- *      SmallBlockChainStream_ReadAt\r
- *\r
- * Reads a specified number of bytes from this chain at the specified offset.\r
- * bytesRead may be NULL.\r
- * Failure will be returned if the specified number of bytes has not been read.\r
- */\r
-BOOL SmallBlockChainStream_ReadAt(\r
-  SmallBlockChainStream* This,\r
-  ULARGE_INTEGER         offset,\r
-  ULONG                  size,\r
-  void*                  buffer,\r
-  ULONG*                 bytesRead)\r
-{\r
-  ULARGE_INTEGER offsetInBigBlockFile;\r
-  ULONG blockNoInSequence =\r
-    offset.u.LowPart / This->parentStorage->smallBlockSize;\r
-\r
-  ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;\r
-  ULONG bytesToReadInBuffer;\r
-  ULONG blockIndex;\r
-  ULONG bytesReadFromBigBlockFile;\r
-  BYTE* bufferWalker;\r
-\r
-  /*\r
-   * This should never happen on a small block file.\r
-   */\r
-  assert(offset.u.HighPart==0);\r
-\r
-  /*\r
-   * Find the first block in the stream that contains part of the buffer.\r
-   */\r
-  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);\r
-\r
-  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))\r
-  {\r
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,\r
-                                                       &blockIndex)))\r
-      return FALSE;\r
-    blockNoInSequence--;\r
-  }\r
-\r
-  /*\r
-   * Start reading the buffer.\r
-   */\r
-  *bytesRead   = 0;\r
-  bufferWalker = buffer;\r
-\r
-  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )\r
-  {\r
-    /*\r
-     * Calculate how many bytes we can copy from this small block.\r
-     */\r
-    bytesToReadInBuffer =\r
-      min(This->parentStorage->smallBlockSize - offsetInBlock, size);\r
-\r
-    /*\r
-     * Calculate the offset of the small block in the small block file.\r
-     */\r
-    offsetInBigBlockFile.u.HighPart  = 0;\r
-    offsetInBigBlockFile.u.LowPart   =\r
-      blockIndex * This->parentStorage->smallBlockSize;\r
-\r
-    offsetInBigBlockFile.u.LowPart  += offsetInBlock;\r
-\r
-    /*\r
-     * Read those bytes in the buffer from the small block file.\r
-     */\r
-    BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,\r
-      offsetInBigBlockFile,\r
-      bytesToReadInBuffer,\r
-      bufferWalker,\r
-      &bytesReadFromBigBlockFile);\r
-\r
-    assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);\r
-\r
-    /*\r
-     * Step to the next big block.\r
-     */\r
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))\r
-      return FALSE;\r
-    bufferWalker += bytesToReadInBuffer;\r
-    size         -= bytesToReadInBuffer;\r
-    *bytesRead   += bytesToReadInBuffer;\r
-    offsetInBlock = 0;  /* There is no offset on the next block */\r
-  }\r
-\r
-  return (size == 0);\r
-}\r
-\r
-/******************************************************************************\r
- *       SmallBlockChainStream_WriteAt\r
- *\r
- * Writes the specified number of bytes to this chain at the specified offset.\r
- * bytesWritten may be NULL.\r
- * Will fail if not all specified number of bytes have been written.\r
- */\r
-BOOL SmallBlockChainStream_WriteAt(\r
-  SmallBlockChainStream* This,\r
-  ULARGE_INTEGER offset,\r
-  ULONG          size,\r
-  const void*    buffer,\r
-  ULONG*         bytesWritten)\r
-{\r
-  ULARGE_INTEGER offsetInBigBlockFile;\r
-  ULONG blockNoInSequence =\r
-    offset.u.LowPart / This->parentStorage->smallBlockSize;\r
-\r
-  ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;\r
-  ULONG bytesToWriteInBuffer;\r
-  ULONG blockIndex;\r
-  ULONG bytesWrittenFromBigBlockFile;\r
-  const BYTE* bufferWalker;\r
-\r
-  /*\r
-   * This should never happen on a small block file.\r
-   */\r
-  assert(offset.u.HighPart==0);\r
-\r
-  /*\r
-   * Find the first block in the stream that contains part of the buffer.\r
-   */\r
-  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);\r
-\r
-  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))\r
-  {\r
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))\r
-      return FALSE;\r
-    blockNoInSequence--;\r
-  }\r
-\r
-  /*\r
-   * Start writing the buffer.\r
-   *\r
-   * Here, I'm casting away the constness on the buffer variable\r
-   * This is OK since we don't intend to modify that buffer.\r
-   */\r
-  *bytesWritten   = 0;\r
-  bufferWalker = (const BYTE*)buffer;\r
-  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )\r
-  {\r
-    /*\r
-     * Calculate how many bytes we can copy to this small block.\r
-     */\r
-    bytesToWriteInBuffer =\r
-      min(This->parentStorage->smallBlockSize - offsetInBlock, size);\r
-\r
-    /*\r
-     * Calculate the offset of the small block in the small block file.\r
-     */\r
-    offsetInBigBlockFile.u.HighPart  = 0;\r
-    offsetInBigBlockFile.u.LowPart   =\r
-      blockIndex * This->parentStorage->smallBlockSize;\r
-\r
-    offsetInBigBlockFile.u.LowPart  += offsetInBlock;\r
-\r
-    /*\r
-     * Write those bytes in the buffer to the small block file.\r
-     */\r
-    BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,\r
-      offsetInBigBlockFile,\r
-      bytesToWriteInBuffer,\r
-      bufferWalker,\r
-      &bytesWrittenFromBigBlockFile);\r
-\r
-    assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);\r
-\r
-    /*\r
-     * Step to the next big block.\r
-     */\r
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,\r
-                                                       &blockIndex)))\r
-      return FALSE;\r
-    bufferWalker  += bytesToWriteInBuffer;\r
-    size          -= bytesToWriteInBuffer;\r
-    *bytesWritten += bytesToWriteInBuffer;\r
-    offsetInBlock  = 0;     /* There is no offset on the next block */\r
-  }\r
-\r
-  return (size == 0);\r
-}\r
-\r
-/******************************************************************************\r
- *       SmallBlockChainStream_Shrink\r
- *\r
- * Shrinks this chain in the small block depot.\r
- */\r
-BOOL SmallBlockChainStream_Shrink(\r
-  SmallBlockChainStream* This,\r
-  ULARGE_INTEGER newSize)\r
-{\r
-  ULONG blockIndex, extraBlock;\r
-  ULONG numBlocks;\r
-  ULONG count = 0;\r
-\r
-  numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;\r
-\r
-  if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)\r
-    numBlocks++;\r
-\r
-  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);\r
-\r
-  /*\r
-   * Go to the new end of chain\r
-   */\r
-  while (count < numBlocks)\r
-  {\r
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,\r
-                                                       &blockIndex)))\r
-      return FALSE;\r
-    count++;\r
-  }\r
-\r
-  /*\r
-   * If the count is 0, we have a special case, the head of the chain was\r
-   * just freed.\r
-   */\r
-  if (count == 0)\r
-  {\r
-    StgProperty chainProp;\r
-\r
-    StorageImpl_ReadProperty(This->parentStorage,\r
-                            This->ownerPropertyIndex,\r
-                            &chainProp);\r
-\r
-    chainProp.startingBlock = BLOCK_END_OF_CHAIN;\r
-\r
-    StorageImpl_WriteProperty(This->parentStorage,\r
-                             This->ownerPropertyIndex,\r
-                             &chainProp);\r
-\r
-    /*\r
-     * We start freeing the chain at the head block.\r
-     */\r
-    extraBlock = blockIndex;\r
-  }\r
-  else\r
-  {\r
-    /* Get the next block before marking the new end */\r
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,\r
-                                                       &extraBlock)))\r
-      return FALSE;\r
-\r
-    /* Mark the new end of chain */\r
-    SmallBlockChainStream_SetNextBlockInChain(\r
-      This,\r
-      blockIndex,\r
-      BLOCK_END_OF_CHAIN);\r
-  }\r
-\r
-  /*\r
-   * Mark the extra blocks as free\r
-   */\r
-  while (extraBlock != BLOCK_END_OF_CHAIN)\r
-  {\r
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,\r
-                                                       &blockIndex)))\r
-      return FALSE;\r
-    SmallBlockChainStream_FreeBlock(This, extraBlock);\r
-    extraBlock = blockIndex;\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *      SmallBlockChainStream_Enlarge\r
- *\r
- * Grows this chain in the small block depot.\r
- */\r
-BOOL SmallBlockChainStream_Enlarge(\r
-  SmallBlockChainStream* This,\r
-  ULARGE_INTEGER newSize)\r
-{\r
-  ULONG blockIndex, currentBlock;\r
-  ULONG newNumBlocks;\r
-  ULONG oldNumBlocks = 0;\r
-\r
-  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);\r
-\r
-  /*\r
-   * Empty chain\r
-   */\r
-  if (blockIndex == BLOCK_END_OF_CHAIN)\r
-  {\r
-\r
-    StgProperty chainProp;\r
-\r
-    StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,\r
-                               &chainProp);\r
-\r
-    chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);\r
-\r
-    StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,\r
-                                &chainProp);\r
-\r
-    blockIndex = chainProp.startingBlock;\r
-    SmallBlockChainStream_SetNextBlockInChain(\r
-      This,\r
-      blockIndex,\r
-      BLOCK_END_OF_CHAIN);\r
-  }\r
-\r
-  currentBlock = blockIndex;\r
-\r
-  /*\r
-   * Figure out how many blocks are needed to contain this stream\r
-   */\r
-  newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;\r
-\r
-  if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)\r
-    newNumBlocks++;\r
-\r
-  /*\r
-   * Go to the current end of chain\r
-   */\r
-  while (blockIndex != BLOCK_END_OF_CHAIN)\r
-  {\r
-    oldNumBlocks++;\r
-    currentBlock = blockIndex;\r
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))\r
-      return FALSE;\r
-  }\r
-\r
-  /*\r
-   * Add new blocks to the chain\r
-   */\r
-  while (oldNumBlocks < newNumBlocks)\r
-  {\r
-    blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);\r
-    SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);\r
-\r
-    SmallBlockChainStream_SetNextBlockInChain(\r
-      This,\r
-      blockIndex,\r
-      BLOCK_END_OF_CHAIN);\r
-\r
-    currentBlock = blockIndex;\r
-    oldNumBlocks++;\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *      SmallBlockChainStream_GetCount\r
- *\r
- * Returns the number of blocks that comprises this chain.\r
- * This is not the size of this chain as the last block may not be full!\r
- */\r
-ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)\r
-{\r
-  ULONG blockIndex;\r
-  ULONG count = 0;\r
-\r
-  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);\r
-\r
-  while (blockIndex != BLOCK_END_OF_CHAIN)\r
-  {\r
-    count++;\r
-\r
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))\r
-      return 0;\r
-  }\r
-\r
-  return count;\r
-}\r
-\r
-/******************************************************************************\r
- *      SmallBlockChainStream_SetSize\r
- *\r
- * Sets the size of this stream.\r
- * The file will grow if we grow the chain.\r
- *\r
- * TODO: Free the actual blocks in the file when we shrink the chain.\r
- *       Currently, the blocks are still in the file. So the file size\r
- *       doesn't shrink even if we shrink streams.\r
- */\r
-BOOL SmallBlockChainStream_SetSize(\r
-                SmallBlockChainStream* This,\r
-                ULARGE_INTEGER    newSize)\r
-{\r
-  ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);\r
-\r
-  if (newSize.u.LowPart == size.u.LowPart)\r
-    return TRUE;\r
-\r
-  if (newSize.u.LowPart < size.u.LowPart)\r
-  {\r
-    SmallBlockChainStream_Shrink(This, newSize);\r
-  }\r
-  else\r
-  {\r
-    SmallBlockChainStream_Enlarge(This, newSize);\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/******************************************************************************\r
- *      SmallBlockChainStream_GetSize\r
- *\r
- * Returns the size of this chain.\r
- */\r
-ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)\r
-{\r
-  StgProperty chainProperty;\r
-\r
-  StorageImpl_ReadProperty(\r
-    This->parentStorage,\r
-    This->ownerPropertyIndex,\r
-    &chainProperty);\r
-\r
-  return chainProperty.size;\r
-}\r
-\r
-/******************************************************************************\r
- *    StgCreateDocfile  [OLE32.@]\r
- */\r
-HRESULT WINAPI StgCreateDocfile(\r
-  LPCOLESTR pwcsName,\r
-  DWORD       grfMode,\r
-  DWORD       reserved,\r
-  IStorage  **ppstgOpen)\r
-{\r
-  StorageImpl* newStorage = 0;\r
-  HANDLE       hFile      = INVALID_HANDLE_VALUE;\r
-  HRESULT        hr         = STG_E_INVALIDFLAG;\r
-  DWORD          shareMode;\r
-  DWORD          accessMode;\r
-  DWORD          creationMode;\r
-  DWORD          fileAttributes;\r
-  WCHAR          tempFileName[MAX_PATH];\r
-\r
-  TRACE("(%s, %lx, %ld, %p)\n",\r
-       debugstr_w(pwcsName), grfMode,\r
-       reserved, ppstgOpen);\r
-\r
-  /*\r
-   * Validate the parameters\r
-   */\r
-  if (ppstgOpen == 0)\r
-    return STG_E_INVALIDPOINTER;\r
-  if (reserved != 0)\r
-    return STG_E_INVALIDPARAMETER;\r
-\r
-  /*\r
-   * Validate the STGM flags\r
-   */\r
-  if ( FAILED( validateSTGM(grfMode) ))\r
-    goto end;\r
-\r
-  /* StgCreateDocFile always opens for write */\r
-  switch(STGM_ACCESS_MODE(grfMode))\r
-  {\r
-  case STGM_WRITE:\r
-  case STGM_READWRITE:\r
-    break;\r
-  default:\r
-    goto end;\r
-  }\r
-\r
-  /* can't share write */\r
-  switch(STGM_SHARE_MODE(grfMode))\r
-  {\r
-  case STGM_SHARE_EXCLUSIVE:\r
-  case STGM_SHARE_DENY_WRITE:\r
-    break;\r
-  default:\r
-    goto end;\r
-  }\r
-\r
-  /* shared reading requires transacted mode */\r
-  if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&\r
-     !(grfMode&STGM_TRANSACTED) )\r
-    goto end;\r
-\r
-  /*\r
-   * Generate a unique name.\r
-   */\r
-  if (pwcsName == 0)\r
-  {\r
-    WCHAR tempPath[MAX_PATH];\r
-    static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };\r
-\r
-    if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)\r
-      goto end;\r
-\r
-    memset(tempPath, 0, sizeof(tempPath));\r
-    memset(tempFileName, 0, sizeof(tempFileName));\r
-\r
-    if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )\r
-      tempPath[0] = '.';\r
-\r
-    if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)\r
-      pwcsName = tempFileName;\r
-    else\r
-    {\r
-      hr = STG_E_INSUFFICIENTMEMORY;\r
-      goto end;\r
-    }\r
-\r
-    creationMode = TRUNCATE_EXISTING;\r
-  }\r
-  else\r
-  {\r
-    creationMode = GetCreationModeFromSTGM(grfMode);\r
-  }\r
-\r
-  /*\r
-   * Interpret the STGM value grfMode\r
-   */\r
-  shareMode    = GetShareModeFromSTGM(grfMode);\r
-  accessMode   = GetAccessModeFromSTGM(grfMode);\r
-\r
-  if (grfMode & STGM_DELETEONRELEASE)\r
-    fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;\r
-  else\r
-    fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;\r
-\r
-  if (grfMode & STGM_TRANSACTED)\r
-    FIXME("Transacted mode not implemented.\n");\r
-\r
-  /*\r
-   * Initialize the "out" parameter.\r
-   */\r
-  *ppstgOpen = 0;\r
-\r
-  hFile = CreateFileW(pwcsName,\r
-                        accessMode,\r
-                        shareMode,\r
-                        NULL,\r
-                        creationMode,\r
-                        fileAttributes,\r
-                        0);\r
-\r
-  if (hFile == INVALID_HANDLE_VALUE)\r
-  {\r
-    if(GetLastError() == ERROR_FILE_EXISTS)\r
-      hr = STG_E_FILEALREADYEXISTS;\r
-    else\r
-      hr = E_FAIL;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Allocate and initialize the new IStorage32object.\r
-   */\r
-  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));\r
-\r
-  if (newStorage == 0)\r
-  {\r
-    hr = STG_E_INSUFFICIENTMEMORY;\r
-    goto end;\r
-  }\r
-\r
-  hr = StorageImpl_Construct(\r
-         newStorage,\r
-         hFile,\r
-        pwcsName,\r
-         NULL,\r
-         grfMode,\r
-         TRUE,\r
-         TRUE);\r
-\r
-  if (FAILED(hr))\r
-  {\r
-    HeapFree(GetProcessHeap(), 0, newStorage);\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Get an "out" pointer for the caller.\r
-   */\r
-  hr = StorageBaseImpl_QueryInterface(\r
-         (IStorage*)newStorage,\r
-         (REFIID)&IID_IStorage,\r
-         (void**)ppstgOpen);\r
-end:\r
-  TRACE("<-- %p  r = %08lx\n", *ppstgOpen, hr);\r
-\r
-  return hr;\r
-}\r
-\r
-/******************************************************************************\r
- *              StgCreateStorageEx        [OLE32.@]\r
- */\r
-HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)\r
-{\r
-    TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName),\r
-          grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);\r
-\r
-    if (stgfmt != STGFMT_FILE && grfAttrs != 0)\r
-    {\r
-        ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");\r
-        return STG_E_INVALIDPARAMETER;  \r
-    }\r
-\r
-    if (stgfmt != STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)\r
-    {\r
-        ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");\r
-        return STG_E_INVALIDPARAMETER;  \r
-    }\r
-\r
-    if (stgfmt == STGFMT_FILE)\r
-    {\r
-        ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  \r
-        return STG_E_INVALIDPARAMETER;\r
-    }\r
-\r
-    if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)\r
-    {\r
-        FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n");\r
-        return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); \r
-    }\r
-\r
-    ERR("Invalid stgfmt argument\n");\r
-    return STG_E_INVALIDPARAMETER;\r
-}\r
-\r
-/******************************************************************************\r
- *              StgCreatePropSetStg       [OLE32.@]\r
- */\r
-HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,\r
- IPropertySetStorage **ppPropSetStg)\r
-{\r
-    HRESULT hr;\r
-\r
-    TRACE("(%p, 0x%lx, %p): stub\n", pstg, reserved, ppPropSetStg);\r
-    if (reserved)\r
-        hr = STG_E_INVALIDPARAMETER;\r
-    else\r
-        hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,\r
-         (void**)ppPropSetStg);\r
-    return hr;\r
-}\r
-\r
-/******************************************************************************\r
- *              StgOpenStorageEx      [OLE32.@]\r
- */\r
-HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)\r
-{\r
-    TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName),\r
-          grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);\r
-\r
-    if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)\r
-    {\r
-        ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");\r
-        return STG_E_INVALIDPARAMETER;  \r
-    }\r
-\r
-    if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)\r
-    {\r
-        ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");\r
-        return STG_E_INVALIDPARAMETER;  \r
-    }\r
-\r
-    if (stgfmt == STGFMT_FILE)\r
-    {\r
-        ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  \r
-        return STG_E_INVALIDPARAMETER;\r
-    }\r
-\r
-    if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE || stgfmt == STGFMT_ANY)\r
-    {\r
-        if (stgfmt == STGFMT_ANY) \r
-            WARN("STGFMT_ANY assuming storage\n");\r
-        FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");\r
-        return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); \r
-    }\r
-\r
-    ERR("Invalid stgfmt argument\n");\r
-    return STG_E_INVALIDPARAMETER;\r
-}\r
-\r
-\r
-/******************************************************************************\r
- *              StgOpenStorage        [OLE32.@]\r
- */\r
-HRESULT WINAPI StgOpenStorage(\r
-  const OLECHAR *pwcsName,\r
-  IStorage      *pstgPriority,\r
-  DWORD           grfMode,\r
-  SNB           snbExclude,\r
-  DWORD           reserved,\r
-  IStorage      **ppstgOpen)\r
-{\r
-  StorageImpl* newStorage = 0;\r
-  HRESULT        hr = S_OK;\r
-  HANDLE       hFile = 0;\r
-  DWORD          shareMode;\r
-  DWORD          accessMode;\r
-  WCHAR          fullname[MAX_PATH];\r
-  DWORD          length;\r
-\r
-  TRACE("(%s, %p, %lx, %p, %ld, %p)\n",\r
-       debugstr_w(pwcsName), pstgPriority, grfMode,\r
-       snbExclude, reserved, ppstgOpen);\r
-\r
-  /*\r
-   * Perform sanity checks\r
-   */\r
-  if (pwcsName == 0)\r
-  {\r
-    hr = STG_E_INVALIDNAME;\r
-    goto end;\r
-  }\r
-\r
-  if (ppstgOpen == 0)\r
-  {\r
-    hr = STG_E_INVALIDPOINTER;\r
-    goto end;\r
-  }\r
-\r
-  if (reserved)\r
-  {\r
-    hr = STG_E_INVALIDPARAMETER;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Validate the sharing mode\r
-   */\r
-  switch(STGM_SHARE_MODE(grfMode))\r
-  {\r
-  case STGM_SHARE_EXCLUSIVE:\r
-  case STGM_SHARE_DENY_WRITE:\r
-    break;\r
-  default:\r
-    hr = STG_E_INVALIDFLAG;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Validate the STGM flags\r
-   */\r
-  if ( FAILED( validateSTGM(grfMode) ) ||\r
-       (grfMode&STGM_CREATE))\r
-  {\r
-    hr = STG_E_INVALIDFLAG;\r
-    goto end;\r
-  }\r
-\r
-  /* shared reading requires transacted mode */\r
-  if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&\r
-      STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&\r
-     !(grfMode&STGM_TRANSACTED) )\r
-  {\r
-    hr = STG_E_INVALIDFLAG;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Interpret the STGM value grfMode\r
-   */\r
-  shareMode    = GetShareModeFromSTGM(grfMode);\r
-  accessMode   = GetAccessModeFromSTGM(grfMode);\r
-\r
-  /*\r
-   * Initialize the "out" parameter.\r
-   */\r
-  *ppstgOpen = 0;\r
-\r
-  hFile = CreateFileW( pwcsName,\r
-                       accessMode,\r
-                       shareMode,\r
-                       NULL,\r
-                       OPEN_EXISTING,\r
-                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,\r
-                       0);\r
-\r
-  if (hFile==INVALID_HANDLE_VALUE)\r
-  {\r
-    DWORD last_error = GetLastError();\r
-\r
-    hr = E_FAIL;\r
-\r
-    switch (last_error)\r
-    {\r
-      case ERROR_FILE_NOT_FOUND:\r
-        hr = STG_E_FILENOTFOUND;\r
-        break;\r
-\r
-      case ERROR_PATH_NOT_FOUND:\r
-        hr = STG_E_PATHNOTFOUND;\r
-        break;\r
-\r
-      case ERROR_ACCESS_DENIED:\r
-      case ERROR_WRITE_PROTECT:\r
-        hr = STG_E_ACCESSDENIED;\r
-        break;\r
-\r
-      case ERROR_SHARING_VIOLATION:\r
-        hr = STG_E_SHAREVIOLATION;\r
-        break;\r
-\r
-      default:\r
-        hr = E_FAIL;\r
-    }\r
-\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Refuse to open the file if it's too small to be a structured storage file\r
-   * FIXME: verify the file when reading instead of here\r
-   */\r
-  length = GetFileSize(hFile, NULL);\r
-  if (length < 0x100)\r
-  {\r
-    CloseHandle(hFile);\r
-    hr = STG_E_FILEALREADYEXISTS;\r
-    goto end;\r
-  }\r
-\r
-  /*\r
-   * Allocate and initialize the new IStorage32object.\r
-   */\r
-  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));\r
-\r
-  if (newStorage == 0)\r
-  {\r
-    hr = STG_E_INSUFFICIENTMEMORY;\r
-    goto end;\r
-  }\r
-\r
-  /* if the file's length was zero, initialize the storage */\r
-  hr = StorageImpl_Construct(\r
-         newStorage,\r
-         hFile,\r
-        pwcsName,\r
-         NULL,\r
-         grfMode,\r
-         TRUE,\r
-        FALSE );\r
-\r
-  if (FAILED(hr))\r
-  {\r
-    HeapFree(GetProcessHeap(), 0, newStorage);\r
-    /*\r
-     * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS\r
-     */\r
-    if(hr == STG_E_INVALIDHEADER)\r
-       hr = STG_E_FILEALREADYEXISTS;\r
-    goto end;\r
-  }\r
-\r
-  /* prepare the file name string given in lieu of the root property name */\r
-  GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL);\r
-  memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN);\r
-  newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0';\r
-\r
-  /*\r
-   * Get an "out" pointer for the caller.\r
-   */\r
-  hr = StorageBaseImpl_QueryInterface(\r
-         (IStorage*)newStorage,\r
-         (REFIID)&IID_IStorage,\r
-         (void**)ppstgOpen);\r
-\r
-end:\r
-  TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);\r
-  return hr;\r
-}\r
-\r
-/******************************************************************************\r
- *    StgCreateDocfileOnILockBytes    [OLE32.@]\r
- */\r
-HRESULT WINAPI StgCreateDocfileOnILockBytes(\r
-      ILockBytes *plkbyt,\r
-      DWORD grfMode,\r
-      DWORD reserved,\r
-      IStorage** ppstgOpen)\r
-{\r
-  StorageImpl*   newStorage = 0;\r
-  HRESULT        hr         = S_OK;\r
-\r
-  /*\r
-   * Validate the parameters\r
-   */\r
-  if ((ppstgOpen == 0) || (plkbyt == 0))\r
-    return STG_E_INVALIDPOINTER;\r
-\r
-  /*\r
-   * Allocate and initialize the new IStorage object.\r
-   */\r
-  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));\r
-\r
-  if (newStorage == 0)\r
-    return STG_E_INSUFFICIENTMEMORY;\r
-\r
-  hr = StorageImpl_Construct(\r
-         newStorage,\r
-         0,\r
-        0,\r
-         plkbyt,\r
-         grfMode,\r
-         FALSE,\r
-         TRUE);\r
-\r
-  if (FAILED(hr))\r
-  {\r
-    HeapFree(GetProcessHeap(), 0, newStorage);\r
-    return hr;\r
-  }\r
-\r
-  /*\r
-   * Get an "out" pointer for the caller.\r
-   */\r
-  hr = StorageBaseImpl_QueryInterface(\r
-         (IStorage*)newStorage,\r
-         (REFIID)&IID_IStorage,\r
-         (void**)ppstgOpen);\r
-\r
-  return hr;\r
-}\r
-\r
-/******************************************************************************\r
- *    StgOpenStorageOnILockBytes    [OLE32.@]\r
- */\r
-HRESULT WINAPI StgOpenStorageOnILockBytes(\r
-      ILockBytes *plkbyt,\r
-      IStorage *pstgPriority,\r
-      DWORD grfMode,\r
-      SNB snbExclude,\r
-      DWORD reserved,\r
-      IStorage **ppstgOpen)\r
-{\r
-  StorageImpl* newStorage = 0;\r
-  HRESULT        hr = S_OK;\r
-\r
-  /*\r
-   * Perform a sanity check\r
-   */\r
-  if ((plkbyt == 0) || (ppstgOpen == 0))\r
-    return STG_E_INVALIDPOINTER;\r
-\r
-  /*\r
-   * Validate the STGM flags\r
-   */\r
-  if ( FAILED( validateSTGM(grfMode) ))\r
-    return STG_E_INVALIDFLAG;\r
-\r
-  /*\r
-   * Initialize the "out" parameter.\r
-   */\r
-  *ppstgOpen = 0;\r
-\r
-  /*\r
-   * Allocate and initialize the new IStorage object.\r
-   */\r
-  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));\r
-\r
-  if (newStorage == 0)\r
-    return STG_E_INSUFFICIENTMEMORY;\r
-\r
-  hr = StorageImpl_Construct(\r
-         newStorage,\r
-         0,\r
-         0,\r
-         plkbyt,\r
-         grfMode,\r
-         FALSE,\r
-         FALSE);\r
-\r
-  if (FAILED(hr))\r
-  {\r
-    HeapFree(GetProcessHeap(), 0, newStorage);\r
-    return hr;\r
-  }\r
-\r
-  /*\r
-   * Get an "out" pointer for the caller.\r
-   */\r
-  hr = StorageBaseImpl_QueryInterface(\r
-         (IStorage*)newStorage,\r
-         (REFIID)&IID_IStorage,\r
-         (void**)ppstgOpen);\r
-\r
-  return hr;\r
-}\r
-\r
-/******************************************************************************\r
- *              StgSetTimes [ole32.@]\r
- *              StgSetTimes [OLE32.@]\r
- *\r
- *\r
- */\r
-HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,\r
-                           FILETIME const *patime, FILETIME const *pmtime)\r
-{\r
-  IStorage *stg = NULL;\r
-  HRESULT r;\r
\r
-  TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);\r
-\r
-  r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,\r
-                     0, 0, &stg);\r
-  if( SUCCEEDED(r) )\r
-  {\r
-    r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);\r
-    IStorage_Release(stg);\r
-  }\r
-\r
-  return r;\r
-}\r
-\r
-/******************************************************************************\r
- *              StgIsStorageILockBytes        [OLE32.@]\r
- *\r
- * Determines if the ILockBytes contains a storage object.\r
- */\r
-HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)\r
-{\r
-  BYTE sig[8];\r
-  ULARGE_INTEGER offset;\r
-\r
-  offset.u.HighPart = 0;\r
-  offset.u.LowPart  = 0;\r
-\r
-  ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);\r
-\r
-  if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)\r
-    return S_OK;\r
-\r
-  return S_FALSE;\r
-}\r
-\r
-/******************************************************************************\r
- *              WriteClassStg        [OLE32.@]\r
- *\r
- * This method will store the specified CLSID in the specified storage object\r
- */\r
-HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)\r
-{\r
-  HRESULT hRes;\r
-\r
-  assert(pStg != 0);\r
-\r
-  hRes = IStorage_SetClass(pStg, rclsid);\r
-\r
-  return hRes;\r
-}\r
-\r
-/***********************************************************************\r
- *    ReadClassStg (OLE32.@)\r
- *\r
- * This method reads the CLSID previously written to a storage object with the WriteClassStg.\r
- */\r
-HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){\r
-\r
-    STATSTG pstatstg;\r
-    HRESULT hRes;\r
-\r
-    TRACE("()\n");\r
-\r
-    if(pclsid==NULL)\r
-        return E_POINTER;\r
-   /*\r
-    * read a STATSTG structure (contains the clsid) from the storage\r
-    */\r
-    hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);\r
-\r
-    if(SUCCEEDED(hRes))\r
-        *pclsid=pstatstg.clsid;\r
-\r
-    return hRes;\r
-}\r
-\r
-/***********************************************************************\r
- *    OleLoadFromStream (OLE32.@)\r
- *\r
- * This function loads an object from stream\r
- */\r
-HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)\r
-{\r
-    CLSID      clsid;\r
-    HRESULT    res;\r
-    LPPERSISTSTREAM    xstm;\r
-\r
-    TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);\r
-\r
-    res=ReadClassStm(pStm,&clsid);\r
-    if (!SUCCEEDED(res))\r
-       return res;\r
-    res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);\r
-    if (!SUCCEEDED(res))\r
-       return res;\r
-    res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);\r
-    if (!SUCCEEDED(res)) {\r
-       IUnknown_Release((IUnknown*)*ppvObj);\r
-       return res;\r
-    }\r
-    res=IPersistStream_Load(xstm,pStm);\r
-    IPersistStream_Release(xstm);\r
-    /* FIXME: all refcounts ok at this point? I think they should be:\r
-     *                 pStm    : unchanged\r
-     *         ppvObj  : 1\r
-     *         xstm    : 0 (released)\r
-     */\r
-    return res;\r
-}\r
-\r
-/***********************************************************************\r
- *    OleSaveToStream (OLE32.@)\r
- *\r
- * This function saves an object with the IPersistStream interface on it\r
- * to the specified stream.\r
- */\r
-HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)\r
-{\r
-\r
-    CLSID clsid;\r
-    HRESULT res;\r
-\r
-    TRACE("(%p,%p)\n",pPStm,pStm);\r
-\r
-    res=IPersistStream_GetClassID(pPStm,&clsid);\r
-\r
-    if (SUCCEEDED(res)){\r
-\r
-        res=WriteClassStm(pStm,&clsid);\r
-\r
-        if (SUCCEEDED(res))\r
-\r
-            res=IPersistStream_Save(pPStm,pStm,TRUE);\r
-    }\r
-\r
-    TRACE("Finished Save\n");\r
-    return res;\r
-}\r
-\r
-/****************************************************************************\r
- * This method validate a STGM parameter that can contain the values below\r
- *\r
- * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.\r
- * The stgm values contained in 0xffff0000 are bitmasks.\r
- *\r
- * STGM_DIRECT               0x00000000\r
- * STGM_TRANSACTED           0x00010000\r
- * STGM_SIMPLE               0x08000000\r
- *\r
- * STGM_READ                 0x00000000\r
- * STGM_WRITE                0x00000001\r
- * STGM_READWRITE            0x00000002\r
- *\r
- * STGM_SHARE_DENY_NONE      0x00000040\r
- * STGM_SHARE_DENY_READ      0x00000030\r
- * STGM_SHARE_DENY_WRITE     0x00000020\r
- * STGM_SHARE_EXCLUSIVE      0x00000010\r
- *\r
- * STGM_PRIORITY             0x00040000\r
- * STGM_DELETEONRELEASE      0x04000000\r
- *\r
- * STGM_CREATE               0x00001000\r
- * STGM_CONVERT              0x00020000\r
- * STGM_FAILIFTHERE          0x00000000\r
- *\r
- * STGM_NOSCRATCH            0x00100000\r
- * STGM_NOSNAPSHOT           0x00200000\r
- */\r
-static HRESULT validateSTGM(DWORD stgm)\r
-{\r
-  DWORD access = STGM_ACCESS_MODE(stgm);\r
-  DWORD share  = STGM_SHARE_MODE(stgm);\r
-  DWORD create = STGM_CREATE_MODE(stgm);\r
-\r
-  if (stgm&~STGM_KNOWN_FLAGS)\r
-  {\r
-    ERR("unknown flags %08lx\n", stgm);\r
-    return E_FAIL;\r
-  }\r
-\r
-  switch (access)\r
-  {\r
-  case STGM_READ:\r
-  case STGM_WRITE:\r
-  case STGM_READWRITE:\r
-    break;\r
-  default:\r
-    return E_FAIL;\r
-  }\r
-\r
-  switch (share)\r
-  {\r
-  case STGM_SHARE_DENY_NONE:\r
-  case STGM_SHARE_DENY_READ:\r
-  case STGM_SHARE_DENY_WRITE:\r
-  case STGM_SHARE_EXCLUSIVE:\r
-    break;\r
-  default:\r
-    return E_FAIL;\r
-  }\r
-\r
-  switch (create)\r
-  {\r
-  case STGM_CREATE:\r
-  case STGM_FAILIFTHERE:\r
-    break;\r
-  default:\r
-    return E_FAIL;\r
-  }\r
-\r
-  /*\r
-   * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE\r
-   */\r
-  if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )\r
-      return E_FAIL;\r
-\r
-  /*\r
-   * STGM_CREATE | STGM_CONVERT\r
-   * if both are false, STGM_FAILIFTHERE is set to TRUE\r
-   */\r
-  if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )\r
-    return E_FAIL;\r
-\r
-  /*\r
-   * STGM_NOSCRATCH requires STGM_TRANSACTED\r
-   */\r
-  if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )\r
-    return E_FAIL;\r
-\r
-  /*\r
-   * STGM_NOSNAPSHOT requires STGM_TRANSACTED and\r
-   * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`\r
-   */\r
-  if ( (stgm & STGM_NOSNAPSHOT) &&\r
-        (!(stgm & STGM_TRANSACTED) ||\r
-         share == STGM_SHARE_EXCLUSIVE ||\r
-         share == STGM_SHARE_DENY_WRITE) )\r
-    return E_FAIL;\r
-\r
-  return S_OK;\r
-}\r
-\r
-/****************************************************************************\r
- *      GetShareModeFromSTGM\r
- *\r
- * This method will return a share mode flag from a STGM value.\r
- * The STGM value is assumed valid.\r
- */\r
-static DWORD GetShareModeFromSTGM(DWORD stgm)\r
-{\r
-  switch (STGM_SHARE_MODE(stgm))\r
-  {\r
-  case STGM_SHARE_DENY_NONE:\r
-    return FILE_SHARE_READ | FILE_SHARE_WRITE;\r
-  case STGM_SHARE_DENY_READ:\r
-    return FILE_SHARE_WRITE;\r
-  case STGM_SHARE_DENY_WRITE:\r
-    return FILE_SHARE_READ;\r
-  case STGM_SHARE_EXCLUSIVE:\r
-    return 0;\r
-  }\r
-  ERR("Invalid share mode!\n");\r
-  assert(0);\r
-  return 0;\r
-}\r
-\r
-/****************************************************************************\r
- *      GetAccessModeFromSTGM\r
- *\r
- * This method will return an access mode flag from a STGM value.\r
- * The STGM value is assumed valid.\r
- */\r
-static DWORD GetAccessModeFromSTGM(DWORD stgm)\r
-{\r
-  switch (STGM_ACCESS_MODE(stgm))\r
-  {\r
-  case STGM_READ:\r
-    return GENERIC_READ;\r
-  case STGM_WRITE:\r
-  case STGM_READWRITE:\r
-    return GENERIC_READ | GENERIC_WRITE;\r
-  }\r
-  ERR("Invalid access mode!\n");\r
-  assert(0);\r
-  return 0;\r
-}\r
-\r
-/****************************************************************************\r
- *      GetCreationModeFromSTGM\r
- *\r
- * This method will return a creation mode flag from a STGM value.\r
- * The STGM value is assumed valid.\r
- */\r
-static DWORD GetCreationModeFromSTGM(DWORD stgm)\r
-{\r
-  switch(STGM_CREATE_MODE(stgm))\r
-  {\r
-  case STGM_CREATE:\r
-    return CREATE_ALWAYS;\r
-  case STGM_CONVERT:\r
-    FIXME("STGM_CONVERT not implemented!\n");\r
-    return CREATE_NEW;\r
-  case STGM_FAILIFTHERE:\r
-    return CREATE_NEW;\r
-  }\r
-  ERR("Invalid create mode!\n");\r
-  assert(0);\r
-  return 0;\r
-}\r
-\r
-\r
-/*************************************************************************\r
- * OLECONVERT_LoadOLE10 [Internal]\r
- *\r
- * Loads the OLE10 STREAM to memory\r
- *\r
- * PARAMS\r
- *     pOleStream   [I] The OLESTREAM\r
- *     pData        [I] Data Structure for the OLESTREAM Data\r
- *\r
- * RETURNS\r
- *     Success:  S_OK\r
- *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get\r
- *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide\r
- *\r
- * NOTES\r
- *     This function is used by OleConvertOLESTREAMToIStorage only.\r
- *\r
- *     Memory allocated for pData must be freed by the caller\r
- */\r
-HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)\r
-{\r
-       DWORD dwSize;\r
-       HRESULT hRes = S_OK;\r
-       int nTryCnt=0;\r
-       int max_try = 6;\r
-\r
-       pData->pData = NULL;\r
-       pData->pstrOleObjFileName = (CHAR *) NULL;\r
-\r
-       for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)\r
-       {\r
-       /* Get the OleID */\r
-       dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));\r
-       if(dwSize != sizeof(pData->dwOleID))\r
-       {\r
-               hRes = CONVERT10_E_OLESTREAM_GET;\r
-       }\r
-       else if(pData->dwOleID != OLESTREAM_ID)\r
-       {\r
-               hRes = CONVERT10_E_OLESTREAM_FMT;\r
-       }\r
-               else\r
-               {\r
-                       hRes = S_OK;\r
-                       break;\r
-               }\r
-       }\r
-\r
-       if(hRes == S_OK)\r
-       {\r
-               /* Get the TypeID...more info needed for this field */\r
-               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));\r
-               if(dwSize != sizeof(pData->dwTypeID))\r
-               {\r
-                       hRes = CONVERT10_E_OLESTREAM_GET;\r
-               }\r
-       }\r
-       if(hRes == S_OK)\r
-       {\r
-               if(pData->dwTypeID != 0)\r
-               {\r
-                       /* Get the length of the OleTypeName */\r
-                       dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));\r
-                       if(dwSize != sizeof(pData->dwOleTypeNameLength))\r
-                       {\r
-                               hRes = CONVERT10_E_OLESTREAM_GET;\r
-                       }\r
-\r
-                       if(hRes == S_OK)\r
-                       {\r
-                               if(pData->dwOleTypeNameLength > 0)\r
-                               {\r
-                                       /* Get the OleTypeName */\r
-                                       dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);\r
-                                       if(dwSize != pData->dwOleTypeNameLength)\r
-                                       {\r
-                                               hRes = CONVERT10_E_OLESTREAM_GET;\r
-                                       }\r
-                               }\r
-                       }\r
-                       if(bStrem1)\r
-                       {\r
-                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));\r
-                               if(dwSize != sizeof(pData->dwOleObjFileNameLength))\r
-                               {\r
-                                       hRes = CONVERT10_E_OLESTREAM_GET;\r
-                               }\r
-                       if(hRes == S_OK)\r
-                       {\r
-                                       if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */\r
-                                               pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);\r
-                                       pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);\r
-                                       if(pData->pstrOleObjFileName)\r
-                                       {\r
-                                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);\r
-                                               if(dwSize != pData->dwOleObjFileNameLength)\r
-                                               {\r
-                                                       hRes = CONVERT10_E_OLESTREAM_GET;\r
-                                               }\r
-                                       }\r
-                                       else\r
-                                               hRes = CONVERT10_E_OLESTREAM_GET;\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               /* Get the Width of the Metafile */\r
-                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));\r
-                               if(dwSize != sizeof(pData->dwMetaFileWidth))\r
-                               {\r
-                                       hRes = CONVERT10_E_OLESTREAM_GET;\r
-                               }\r
-                       if(hRes == S_OK)\r
-                       {\r
-                               /* Get the Height of the Metafile */\r
-                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));\r
-                               if(dwSize != sizeof(pData->dwMetaFileHeight))\r
-                               {\r
-                                       hRes = CONVERT10_E_OLESTREAM_GET;\r
-                               }\r
-                       }\r
-                       }\r
-                       if(hRes == S_OK)\r
-                       {\r
-                               /* Get the Length of the Data */\r
-                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));\r
-                               if(dwSize != sizeof(pData->dwDataLength))\r
-                               {\r
-                                       hRes = CONVERT10_E_OLESTREAM_GET;\r
-                               }\r
-                       }\r
-\r
-                       if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */\r
-                       {\r
-                               if(!bStrem1) /* if it is a second OLE stream data */\r
-                               {\r
-                                       pData->dwDataLength -= 8;\r
-                                       dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));\r
-                                       if(dwSize != sizeof(pData->strUnknown))\r
-                                       {\r
-                                               hRes = CONVERT10_E_OLESTREAM_GET;\r
-                                       }\r
-                               }\r
-                       }\r
-                       if(hRes == S_OK)\r
-                       {\r
-                               if(pData->dwDataLength > 0)\r
-                               {\r
-                                       pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);\r
-\r
-                                       /* Get Data (ex. IStorage, Metafile, or BMP) */\r
-                                       if(pData->pData)\r
-                                       {\r
-                                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);\r
-                                               if(dwSize != pData->dwDataLength)\r
-                                               {\r
-                                                       hRes = CONVERT10_E_OLESTREAM_GET;\r
-                                               }\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               hRes = CONVERT10_E_OLESTREAM_GET;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       return hRes;\r
-}\r
-\r
-/*************************************************************************\r
- * OLECONVERT_SaveOLE10 [Internal]\r
- *\r
- * Saves the OLE10 STREAM From memory\r
- *\r
- * PARAMS\r
- *     pData        [I] Data Structure for the OLESTREAM Data\r
- *     pOleStream   [I] The OLESTREAM to save\r
- *\r
- * RETURNS\r
- *     Success:  S_OK\r
- *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put\r
- *\r
- * NOTES\r
- *     This function is used by OleConvertIStorageToOLESTREAM only.\r
- *\r
- */\r
-HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)\r
-{\r
-    DWORD dwSize;\r
-    HRESULT hRes = S_OK;\r
-\r
-\r
-   /* Set the OleID */\r
-    dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));\r
-    if(dwSize != sizeof(pData->dwOleID))\r
-    {\r
-        hRes = CONVERT10_E_OLESTREAM_PUT;\r
-    }\r
-\r
-    if(hRes == S_OK)\r
-    {\r
-        /* Set the TypeID */\r
-        dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));\r
-        if(dwSize != sizeof(pData->dwTypeID))\r
-        {\r
-            hRes = CONVERT10_E_OLESTREAM_PUT;\r
-        }\r
-    }\r
-\r
-    if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)\r
-    {\r
-        /* Set the Length of the OleTypeName */\r
-        dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));\r
-        if(dwSize != sizeof(pData->dwOleTypeNameLength))\r
-        {\r
-            hRes = CONVERT10_E_OLESTREAM_PUT;\r
-        }\r
-\r
-        if(hRes == S_OK)\r
-        {\r
-            if(pData->dwOleTypeNameLength > 0)\r
-            {\r
-                /* Set the OleTypeName */\r
-                dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->strOleTypeName, pData->dwOleTypeNameLength);\r
-                if(dwSize != pData->dwOleTypeNameLength)\r
-                {\r
-                    hRes = CONVERT10_E_OLESTREAM_PUT;\r
-                }\r
-            }\r
-        }\r
-\r
-        if(hRes == S_OK)\r
-        {\r
-            /* Set the width of the Metafile */\r
-            dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));\r
-            if(dwSize != sizeof(pData->dwMetaFileWidth))\r
-            {\r
-                hRes = CONVERT10_E_OLESTREAM_PUT;\r
-            }\r
-        }\r
-\r
-        if(hRes == S_OK)\r
-        {\r
-            /* Set the height of the Metafile */\r
-            dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));\r
-            if(dwSize != sizeof(pData->dwMetaFileHeight))\r
-            {\r
-                hRes = CONVERT10_E_OLESTREAM_PUT;\r
-            }\r
-        }\r
-\r
-        if(hRes == S_OK)\r
-        {\r
-            /* Set the length of the Data */\r
-            dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));\r
-            if(dwSize != sizeof(pData->dwDataLength))\r
-            {\r
-                hRes = CONVERT10_E_OLESTREAM_PUT;\r
-            }\r
-        }\r
-\r
-        if(hRes == S_OK)\r
-        {\r
-            if(pData->dwDataLength > 0)\r
-            {\r
-                /* Set the Data (eg. IStorage, Metafile, Bitmap) */\r
-                dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);\r
-                if(dwSize != pData->dwDataLength)\r
-                {\r
-                    hRes = CONVERT10_E_OLESTREAM_PUT;\r
-                }\r
-            }\r
-        }\r
-    }\r
-    return hRes;\r
-}\r
-\r
-/*************************************************************************\r
- * OLECONVERT_GetOLE20FromOLE10[Internal]\r
- *\r
- * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,\r
- * opens it, and copies the content to the dest IStorage for\r
- * OleConvertOLESTREAMToIStorage\r
- *\r
- *\r
- * PARAMS\r
- *     pDestStorage  [I] The IStorage to copy the data to\r
- *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM\r
- *     nBufferLength [I] The size of the buffer\r
- *\r
- * RETURNS\r
- *     Nothing\r
- *\r
- * NOTES\r
- *\r
- *\r
- */\r
-void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)\r
-{\r
-    HRESULT hRes;\r
-    HANDLE hFile;\r
-    IStorage *pTempStorage;\r
-    DWORD dwNumOfBytesWritten;\r
-    WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];\r
-    static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};\r
-\r
-    /* Create a temp File */\r
-    GetTempPathW(MAX_PATH, wstrTempDir);\r
-    GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);\r
-    hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);\r
-\r
-    if(hFile != INVALID_HANDLE_VALUE)\r
-    {\r
-        /* Write IStorage Data to File */\r
-        WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);\r
-        CloseHandle(hFile);\r
-\r
-        /* Open and copy temp storage to the Dest Storage */\r
-        hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);\r
-        if(hRes == S_OK)\r
-        {\r
-            hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);\r
-            StorageBaseImpl_Release(pTempStorage);\r
-        }\r
-        DeleteFileW(wstrTempFile);\r
-    }\r
-}\r
-\r
-\r
-/*************************************************************************\r
- * OLECONVERT_WriteOLE20ToBuffer [Internal]\r
- *\r
- * Saves the OLE10 STREAM From memory\r
- *\r
- * PARAMS\r
- *     pStorage  [I] The Src IStorage to copy\r
- *     pData     [I] The Dest Memory to write to.\r
- *\r
- * RETURNS\r
- *     The size in bytes allocated for pData\r
- *\r
- * NOTES\r
- *     Memory allocated for pData must be freed by the caller\r
- *\r
- *     Used by OleConvertIStorageToOLESTREAM only.\r
- *\r
- */\r
-DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)\r
-{\r
-    HANDLE hFile;\r
-    HRESULT hRes;\r
-    DWORD nDataLength = 0;\r
-    IStorage *pTempStorage;\r
-    WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];\r
-    static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};\r
-\r
-    *pData = NULL;\r
-\r
-    /* Create temp Storage */\r
-    GetTempPathW(MAX_PATH, wstrTempDir);\r
-    GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);\r
-    hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);\r
-\r
-    if(hRes == S_OK)\r
-    {\r
-        /* Copy Src Storage to the Temp Storage */\r
-        StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);\r
-        StorageBaseImpl_Release(pTempStorage);\r
-\r
-        /* Open Temp Storage as a file and copy to memory */\r
-        hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);\r
-        if(hFile != INVALID_HANDLE_VALUE)\r
-        {\r
-            nDataLength = GetFileSize(hFile, NULL);\r
-            *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);\r
-            ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);\r
-            CloseHandle(hFile);\r
-        }\r
-        DeleteFileW(wstrTempFile);\r
-    }\r
-    return nDataLength;\r
-}\r
-\r
-/*************************************************************************\r
- * OLECONVERT_CreateOleStream [Internal]\r
- *\r
- * Creates the "\001OLE" stream in the IStorage if necessary.\r
- *\r
- * PARAMS\r
- *     pStorage     [I] Dest storage to create the stream in\r
- *\r
- * RETURNS\r
- *     Nothing\r
- *\r
- * NOTES\r
- *     This function is used by OleConvertOLESTREAMToIStorage only.\r
- *\r
- *     This stream is still unknown, MS Word seems to have extra data\r
- *     but since the data is stored in the OLESTREAM there should be\r
- *     no need to recreate the stream.  If the stream is manually\r
- *     deleted it will create it with this default data.\r
- *\r
- */\r
-void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)\r
-{\r
-    HRESULT hRes;\r
-    IStream *pStream;\r
-    static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};\r
-    BYTE pOleStreamHeader [] =\r
-    {\r
-        0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,\r
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
-        0x00, 0x00, 0x00, 0x00\r
-    };\r
-\r
-    /* Create stream if not present */\r
-    hRes = IStorage_CreateStream(pStorage, wstrStreamName,\r
-        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );\r
-\r
-    if(hRes == S_OK)\r
-    {\r
-        /* Write default Data */\r
-        hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);\r
-        IStream_Release(pStream);\r
-    }\r
-}\r
-\r
-/* write a string to a stream, preceded by its length */\r
-static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )\r
-{\r
-    HRESULT r;\r
-    LPSTR str;\r
-    DWORD len = 0;\r
-\r
-    if( string )\r
-        len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);\r
-    r = IStream_Write( stm, &len, sizeof(len), NULL);\r
-    if( FAILED( r ) )\r
-        return r;\r
-    if(len == 0)\r
-        return r;\r
-    str = CoTaskMemAlloc( len );\r
-    WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);\r
-    r = IStream_Write( stm, str, len, NULL);\r
-    CoTaskMemFree( str );\r
-    return r;\r
-}\r
-\r
-/* read a string preceded by its length from a stream */\r
-static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )\r
-{\r
-    HRESULT r;\r
-    DWORD len, count = 0;\r
-    LPSTR str;\r
-    LPWSTR wstr;\r
-\r
-    r = IStream_Read( stm, &len, sizeof(len), &count );\r
-    if( FAILED( r ) )\r
-        return r;\r
-    if( count != sizeof(len) )\r
-        return E_OUTOFMEMORY;\r
-\r
-    TRACE("%ld bytes\n",len);\r
-    \r
-    str = CoTaskMemAlloc( len );\r
-    if( !str )\r
-        return E_OUTOFMEMORY;\r
-    count = 0;\r
-    r = IStream_Read( stm, str, len, &count );\r
-    if( FAILED( r ) )\r
-        return r;\r
-    if( count != len )\r
-    {\r
-        CoTaskMemFree( str );\r
-        return E_OUTOFMEMORY;\r
-    }\r
-\r
-    TRACE("Read string %s\n",debugstr_an(str,len));\r
-\r
-    len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );\r
-    wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );\r
-    if( wstr )\r
-         MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );\r
-    CoTaskMemFree( str );\r
-\r
-    *string = wstr;\r
-\r
-    return r;\r
-}\r
-\r
-\r
-static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,\r
-    LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )\r
-{\r
-    IStream *pstm;\r
-    HRESULT r = S_OK;\r
-    static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};\r
-\r
-    static const BYTE unknown1[12] =\r
-       { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,\r
-         0xFF, 0xFF, 0xFF, 0xFF};\r
-    static const BYTE unknown2[16] =\r
-       { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,\r
-         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\r
-\r
-    TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),\r
-           debugstr_w(lpszUserType), debugstr_w(szClipName),\r
-           debugstr_w(szProgIDName));\r
-\r
-    /*  Create a CompObj stream if it doesn't exist */\r
-    r = IStorage_CreateStream(pstg, szwStreamName,\r
-        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );\r
-    if( FAILED (r) )\r
-        return r;\r
-\r
-    /* Write CompObj Structure to stream */\r
-    r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);\r
-\r
-    if( SUCCEEDED( r ) )\r
-        r = WriteClassStm( pstm, clsid );\r
-\r
-    if( SUCCEEDED( r ) )\r
-        r = STREAM_WriteString( pstm, lpszUserType );\r
-    if( SUCCEEDED( r ) )\r
-        r = STREAM_WriteString( pstm, szClipName );\r
-    if( SUCCEEDED( r ) )\r
-        r = STREAM_WriteString( pstm, szProgIDName );\r
-    if( SUCCEEDED( r ) )\r
-        r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);\r
-\r
-    IStream_Release( pstm );\r
-\r
-    return r;\r
-}\r
-\r
-/***********************************************************************\r
- *               WriteFmtUserTypeStg (OLE32.@)\r
- */\r
-HRESULT WINAPI WriteFmtUserTypeStg(\r
-         LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)\r
-{\r
-    HRESULT r;\r
-    WCHAR szwClipName[0x40];\r
-    CLSID clsid = CLSID_NULL;\r
-    LPWSTR wstrProgID = NULL;\r
-    DWORD n;\r
-\r
-    TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));\r
-\r
-    /* get the clipboard format name */\r
-    n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) );\r
-    szwClipName[n]=0;\r
-\r
-    TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));\r
-\r
-    /* FIXME: There's room to save a CLSID and its ProgID, but\r
-       the CLSID is not looked up in the registry and in all the\r
-       tests I wrote it was CLSID_NULL.  Where does it come from?\r
-    */\r
-\r
-    /* get the real program ID.  This may fail, but that's fine */\r
-    ProgIDFromCLSID(&clsid, &wstrProgID);\r
-\r
-    TRACE("progid is %s\n",debugstr_w(wstrProgID));\r
-\r
-    r = STORAGE_WriteCompObj( pstg, &clsid, \r
-                              lpszUserType, szwClipName, wstrProgID );\r
-\r
-    CoTaskMemFree(wstrProgID);\r
-\r
-    return r;\r
-}\r
-\r
-\r
-/******************************************************************************\r
- *              ReadFmtUserTypeStg        [OLE32.@]\r
- */\r
-HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)\r
-{\r
-    HRESULT r;\r
-    IStream *stm = 0;\r
-    static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };\r
-    unsigned char unknown1[12];\r
-    unsigned char unknown2[16];\r
-    DWORD count;\r
-    LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;\r
-    CLSID clsid;\r
-\r
-    TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);\r
-\r
-    r = IStorage_OpenStream( pstg, szCompObj, NULL, \r
-                    STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );\r
-    if( FAILED ( r ) )\r
-    {\r
-        WARN("Failed to open stream r = %08lx\n", r);\r
-        return r;\r
-    }\r
-\r
-    /* read the various parts of the structure */\r
-    r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );\r
-    if( FAILED( r ) || ( count != sizeof(unknown1) ) )\r
-        goto end;\r
-    r = ReadClassStm( stm, &clsid );\r
-    if( FAILED( r ) )\r
-        goto end;\r
-\r
-    r = STREAM_ReadString( stm, &szCLSIDName );\r
-    if( FAILED( r ) )\r
-        goto end;\r
-\r
-    r = STREAM_ReadString( stm, &szOleTypeName );\r
-    if( FAILED( r ) )\r
-        goto end;\r
-\r
-    r = STREAM_ReadString( stm, &szProgIDName );\r
-    if( FAILED( r ) )\r
-        goto end;\r
-\r
-    r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );\r
-    if( FAILED( r ) || ( count != sizeof(unknown2) ) )\r
-        goto end;\r
-\r
-    /* ok, success... now we just need to store what we found */\r
-    if( pcf )\r
-        *pcf = RegisterClipboardFormatW( szOleTypeName );\r
-    CoTaskMemFree( szOleTypeName );\r
-\r
-    if( lplpszUserType )\r
-        *lplpszUserType = szCLSIDName;\r
-    CoTaskMemFree( szProgIDName );\r
-\r
-end:\r
-    IStream_Release( stm );\r
-\r
-    return r;\r
-}\r
-\r
-\r
-/*************************************************************************\r
- * OLECONVERT_CreateCompObjStream [Internal]\r
- *\r
- * Creates a "\001CompObj" is the destination IStorage if necessary.\r
- *\r
- * PARAMS\r
- *     pStorage       [I] The dest IStorage to create the CompObj Stream\r
- *                        if necessary.\r
- *     strOleTypeName [I] The ProgID\r
- *\r
- * RETURNS\r
- *     Success:  S_OK\r
- *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream\r
- *\r
- * NOTES\r
- *     This function is used by OleConvertOLESTREAMToIStorage only.\r
- *\r
- *     The stream data is stored in the OLESTREAM and there should be\r
- *     no need to recreate the stream.  If the stream is manually\r
- *     deleted it will attempt to create it by querying the registry.\r
- *\r
- *\r
- */\r
-HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)\r
-{\r
-    IStream *pStream;\r
-    HRESULT hStorageRes, hRes = S_OK;\r
-    OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;\r
-    static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};\r
-    WCHAR bufferW[OLESTREAM_MAX_STR_LEN];\r
-\r
-    BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};\r
-    BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};\r
-\r
-    /* Initialize the CompObj structure */\r
-    memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));\r
-    memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));\r
-    memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));\r
-\r
-\r
-    /*  Create a CompObj stream if it doesn't exist */\r
-    hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,\r
-        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );\r
-    if(hStorageRes == S_OK)\r
-    {\r
-        /* copy the OleTypeName to the compobj struct */\r
-        IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;\r
-        strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);\r
-\r
-        /* copy the OleTypeName to the compobj struct */\r
-        /* Note: in the test made, these were Identical      */\r
-        IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;\r
-        strcpy(IStorageCompObj.strProgIDName, strOleTypeName);\r
-\r
-        /* Get the CLSID */\r
-        MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,\r
-                             bufferW, OLESTREAM_MAX_STR_LEN );\r
-        hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));\r
-\r
-        if(hRes == S_OK)\r
-        {\r
-            HKEY hKey;\r
-            LONG hErr;\r
-            /* Get the CLSID Default Name from the Registry */\r
-            hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);\r
-            if(hErr == ERROR_SUCCESS)\r
-            {\r
-                char strTemp[OLESTREAM_MAX_STR_LEN];\r
-                IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;\r
-                hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength));\r
-                if(hErr == ERROR_SUCCESS)\r
-                {\r
-                    strcpy(IStorageCompObj.strCLSIDName, strTemp);\r
-                }\r
-                RegCloseKey(hKey);\r
-            }\r
-        }\r
-\r
-        /* Write CompObj Structure to stream */\r
-        hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);\r
-\r
-        WriteClassStm(pStream,&(IStorageCompObj.clsid));\r
-\r
-        hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);\r
-        if(IStorageCompObj.dwCLSIDNameLength > 0)\r
-        {\r
-            hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);\r
-        }\r
-        hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);\r
-        if(IStorageCompObj.dwOleTypeNameLength > 0)\r
-        {\r
-            hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);\r
-        }\r
-        hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);\r
-        if(IStorageCompObj.dwProgIDNameLength > 0)\r
-        {\r
-            hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);\r
-        }\r
-        hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);\r
-        IStream_Release(pStream);\r
-    }\r
-    return hRes;\r
-}\r
-\r
-\r
-/*************************************************************************\r
- * OLECONVERT_CreateOlePresStream[Internal]\r
- *\r
- * Creates the "\002OlePres000" Stream with the Metafile data\r
- *\r
- * PARAMS\r
- *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.\r
- *     dwExtentX    [I] Width of the Metafile\r
- *     dwExtentY    [I] Height of the Metafile\r
- *     pData        [I] Metafile data\r
- *     dwDataLength [I] Size of the Metafile data\r
- *\r
- * RETURNS\r
- *     Success:  S_OK\r
- *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put\r
- *\r
- * NOTES\r
- *     This function is used by OleConvertOLESTREAMToIStorage only.\r
- *\r
- */\r
-void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)\r
-{\r
-    HRESULT hRes;\r
-    IStream *pStream;\r
-    static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};\r
-    BYTE pOlePresStreamHeader [] =\r
-    {\r
-        0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,\r
-        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\r
-        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,\r
-        0x00, 0x00, 0x00, 0x00\r
-    };\r
-\r
-    BYTE pOlePresStreamHeaderEmpty [] =\r
-    {\r
-        0x00, 0x00, 0x00, 0x00,\r
-        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\r
-        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,\r
-        0x00, 0x00, 0x00, 0x00\r
-    };\r
-\r
-    /* Create the OlePres000 Stream */\r
-    hRes = IStorage_CreateStream(pStorage, wstrStreamName,\r
-        STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );\r
-\r
-    if(hRes == S_OK)\r
-    {\r
-        DWORD nHeaderSize;\r
-        OLECONVERT_ISTORAGE_OLEPRES OlePres;\r
-\r
-        memset(&OlePres, 0, sizeof(OlePres));\r
-        /* Do we have any metafile data to save */\r
-        if(dwDataLength > 0)\r
-        {\r
-            memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));\r
-            nHeaderSize = sizeof(pOlePresStreamHeader);\r
-        }\r
-        else\r
-        {\r
-            memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));\r
-            nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);\r
-        }\r
-        /* Set width and height of the metafile */\r
-        OlePres.dwExtentX = dwExtentX;\r
-        OlePres.dwExtentY = -dwExtentY;\r
-\r
-        /* Set Data and Length */\r
-        if(dwDataLength > sizeof(METAFILEPICT16))\r
-        {\r
-            OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);\r
-            OlePres.pData = &(pData[8]);\r
-        }\r
-        /* Save OlePres000 Data to Stream */\r
-        hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);\r
-        hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);\r
-        hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);\r
-        hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);\r
-        if(OlePres.dwSize > 0)\r
-        {\r
-            hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);\r
-        }\r
-        IStream_Release(pStream);\r
-    }\r
-}\r
-\r
-/*************************************************************************\r
- * OLECONVERT_CreateOle10NativeStream [Internal]\r
- *\r
- * Creates the "\001Ole10Native" Stream (should contain a BMP)\r
- *\r
- * PARAMS\r
- *     pStorage     [I] Dest storage to create the stream in\r
- *     pData        [I] Ole10 Native Data (ex. bmp)\r
- *     dwDataLength [I] Size of the Ole10 Native Data\r
- *\r
- * RETURNS\r
- *     Nothing\r
- *\r
- * NOTES\r
- *     This function is used by OleConvertOLESTREAMToIStorage only.\r
- *\r
- *     Might need to verify the data and return appropriate error message\r
- *\r
- */\r
-void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)\r
-{\r
-    HRESULT hRes;\r
-    IStream *pStream;\r
-    static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};\r
-\r
-    /* Create the Ole10Native Stream */\r
-    hRes = IStorage_CreateStream(pStorage, wstrStreamName,\r
-        STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );\r
-\r
-    if(hRes == S_OK)\r
-    {\r
-        /* Write info to stream */\r
-        hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);\r
-        hRes = IStream_Write(pStream, pData, dwDataLength, NULL);\r
-        IStream_Release(pStream);\r
-    }\r
-\r
-}\r
-\r
-/*************************************************************************\r
- * OLECONVERT_GetOLE10ProgID [Internal]\r
- *\r
- * Finds the ProgID (or OleTypeID) from the IStorage\r
- *\r
- * PARAMS\r
- *     pStorage        [I] The Src IStorage to get the ProgID\r
- *     strProgID       [I] the ProgID string to get\r
- *     dwSize          [I] the size of the string\r
- *\r
- * RETURNS\r
- *     Success:  S_OK\r
- *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream\r
- *\r
- * NOTES\r
- *     This function is used by OleConvertIStorageToOLESTREAM only.\r
- *\r
- *\r
- */\r
-HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)\r
-{\r
-    HRESULT hRes;\r
-    IStream *pStream;\r
-    LARGE_INTEGER iSeekPos;\r
-    OLECONVERT_ISTORAGE_COMPOBJ CompObj;\r
-    static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};\r
-\r
-    /* Open the CompObj Stream */\r
-    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,\r
-        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );\r
-    if(hRes == S_OK)\r
-    {\r
-\r
-        /*Get the OleType from the CompObj Stream */\r
-        iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);\r
-        iSeekPos.u.HighPart = 0;\r
-\r
-        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);\r
-        IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);\r
-        iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;\r
-        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);\r
-        IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);\r
-        iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;\r
-        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);\r
-\r
-        IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);\r
-        if(*dwSize > 0)\r
-        {\r
-            IStream_Read(pStream, strProgID, *dwSize, NULL);\r
-        }\r
-        IStream_Release(pStream);\r
-    }\r
-    else\r
-    {\r
-        STATSTG stat;\r
-        LPOLESTR wstrProgID;\r
-\r
-        /* Get the OleType from the registry */\r
-        REFCLSID clsid = &(stat.clsid);\r
-        IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);\r
-        hRes = ProgIDFromCLSID(clsid, &wstrProgID);\r
-        if(hRes == S_OK)\r
-        {\r
-            *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);\r
-        }\r
-\r
-    }\r
-    return hRes;\r
-}\r
-\r
-/*************************************************************************\r
- * OLECONVERT_GetOle10PresData [Internal]\r
- *\r
- * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream\r
- *\r
- * PARAMS\r
- *     pStorage     [I] Src IStroage\r
- *     pOleStream   [I] Dest OleStream Mem Struct\r
- *\r
- * RETURNS\r
- *     Nothing\r
- *\r
- * NOTES\r
- *     This function is used by OleConvertIStorageToOLESTREAM only.\r
- *\r
- *     Memory allocated for pData must be freed by the caller\r
- *\r
- *\r
- */\r
-void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)\r
-{\r
-\r
-    HRESULT hRes;\r
-    IStream *pStream;\r
-    static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};\r
-\r
-    /* Initialize Default data for OLESTREAM */\r
-    pOleStreamData[0].dwOleID = OLESTREAM_ID;\r
-    pOleStreamData[0].dwTypeID = 2;\r
-    pOleStreamData[1].dwOleID = OLESTREAM_ID;\r
-    pOleStreamData[1].dwTypeID = 0;\r
-    pOleStreamData[0].dwMetaFileWidth = 0;\r
-    pOleStreamData[0].dwMetaFileHeight = 0;\r
-    pOleStreamData[0].pData = NULL;\r
-    pOleStreamData[1].pData = NULL;\r
-\r
-    /* Open Ole10Native Stream */\r
-    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,\r
-        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );\r
-    if(hRes == S_OK)\r
-    {\r
-\r
-        /* Read Size and Data */\r
-        IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);\r
-        if(pOleStreamData->dwDataLength > 0)\r
-        {\r
-            pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);\r
-            IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);\r
-        }\r
-        IStream_Release(pStream);\r
-    }\r
-\r
-}\r
-\r
-\r
-/*************************************************************************\r
- * OLECONVERT_GetOle20PresData[Internal]\r
- *\r
- * Converts IStorage "/002OlePres000" stream to a OLE10 Stream\r
- *\r
- * PARAMS\r
- *     pStorage         [I] Src IStroage\r
- *     pOleStreamData   [I] Dest OleStream Mem Struct\r
- *\r
- * RETURNS\r
- *     Nothing\r
- *\r
- * NOTES\r
- *     This function is used by OleConvertIStorageToOLESTREAM only.\r
- *\r
- *     Memory allocated for pData must be freed by the caller\r
- */\r
-void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)\r
-{\r
-    HRESULT hRes;\r
-    IStream *pStream;\r
-    OLECONVERT_ISTORAGE_OLEPRES olePress;\r
-    static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};\r
-\r
-    /* Initialize Default data for OLESTREAM */\r
-    pOleStreamData[0].dwOleID = OLESTREAM_ID;\r
-    pOleStreamData[0].dwTypeID = 2;\r
-    pOleStreamData[0].dwMetaFileWidth = 0;\r
-    pOleStreamData[0].dwMetaFileHeight = 0;\r
-    pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));\r
-    pOleStreamData[1].dwOleID = OLESTREAM_ID;\r
-    pOleStreamData[1].dwTypeID = 0;\r
-    pOleStreamData[1].dwOleTypeNameLength = 0;\r
-    pOleStreamData[1].strOleTypeName[0] = 0;\r
-    pOleStreamData[1].dwMetaFileWidth = 0;\r
-    pOleStreamData[1].dwMetaFileHeight = 0;\r
-    pOleStreamData[1].pData = NULL;\r
-    pOleStreamData[1].dwDataLength = 0;\r
-\r
-\r
-    /* Open OlePress000 stream */\r
-    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,\r
-        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );\r
-    if(hRes == S_OK)\r
-    {\r
-        LARGE_INTEGER iSeekPos;\r
-        METAFILEPICT16 MetaFilePict;\r
-        static const char strMetafilePictName[] = "METAFILEPICT";\r
-\r
-        /* Set the TypeID for a Metafile */\r
-        pOleStreamData[1].dwTypeID = 5;\r
-\r
-        /* Set the OleTypeName to Metafile */\r
-        pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;\r
-        strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);\r
-\r
-        iSeekPos.u.HighPart = 0;\r
-        iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);\r
-\r
-        /* Get Presentation Data */\r
-        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);\r
-        IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);\r
-        IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);\r
-        IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);\r
-\r
-        /*Set width and Height */\r
-        pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;\r
-        pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;\r
-        if(olePress.dwSize > 0)\r
-        {\r
-            /* Set Length */\r
-            pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);\r
-\r
-            /* Set MetaFilePict struct */\r
-            MetaFilePict.mm = 8;\r
-            MetaFilePict.xExt = olePress.dwExtentX;\r
-            MetaFilePict.yExt = olePress.dwExtentY;\r
-            MetaFilePict.hMF = 0;\r
-\r
-            /* Get Metafile Data */\r
-            pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);\r
-            memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));\r
-            IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);\r
-        }\r
-        IStream_Release(pStream);\r
-    }\r
-}\r
-\r
-/*************************************************************************\r
- * OleConvertOLESTREAMToIStorage [OLE32.@]\r
- *\r
- * Read info on MSDN\r
- *\r
- * TODO\r
- *      DVTARGETDEVICE paramenter is not handled\r
- *      Still unsure of some mem fields for OLE 10 Stream\r
- *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",\r
- *      and "\001OLE" streams\r
- *\r
- */\r
-HRESULT WINAPI OleConvertOLESTREAMToIStorage (\r
-    LPOLESTREAM pOleStream,\r
-    LPSTORAGE pstg,\r
-    const DVTARGETDEVICE* ptd)\r
-{\r
-    int i;\r
-    HRESULT hRes=S_OK;\r
-    OLECONVERT_OLESTREAM_DATA pOleStreamData[2];\r
-\r
-    memset(pOleStreamData, 0, sizeof(pOleStreamData));\r
-\r
-    if(ptd != NULL)\r
-    {\r
-        FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");\r
-    }\r
-\r
-    if(pstg == NULL || pOleStream == NULL)\r
-    {\r
-        hRes = E_INVALIDARG;\r
-    }\r
-\r
-    if(hRes == S_OK)\r
-    {\r
-        /* Load the OLESTREAM to Memory */\r
-        hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);\r
-    }\r
-\r
-    if(hRes == S_OK)\r
-    {\r
-        /* Load the OLESTREAM to Memory (part 2)*/\r
-        hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);\r
-    }\r
-\r
-    if(hRes == S_OK)\r
-    {\r
-\r
-        if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))\r
-        {\r
-            /* Do we have the IStorage Data in the OLESTREAM */\r
-            if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)\r
-            {\r
-                OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);\r
-                OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);\r
-            }\r
-            else\r
-            {\r
-                /* It must be an original OLE 1.0 source */\r
-                OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);\r
-            }\r
-        }\r
-        else\r
-        {\r
-            /* It must be an original OLE 1.0 source */\r
-            OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);\r
-        }\r
-\r
-        /* Create CompObj Stream if necessary */\r
-        hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);\r
-        if(hRes == S_OK)\r
-        {\r
-            /*Create the Ole Stream if necessary */\r
-            OLECONVERT_CreateOleStream(pstg);\r
-        }\r
-    }\r
-\r
-\r
-    /* Free allocated memory */\r
-    for(i=0; i < 2; i++)\r
-    {\r
-        HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);\r
-        HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);\r
-        pOleStreamData[i].pstrOleObjFileName = NULL;\r
-    }\r
-    return hRes;\r
-}\r
-\r
-/*************************************************************************\r
- * OleConvertIStorageToOLESTREAM [OLE32.@]\r
- *\r
- * Read info on MSDN\r
- *\r
- * Read info on MSDN\r
- *\r
- * TODO\r
- *      Still unsure of some mem fields for OLE 10 Stream\r
- *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",\r
- *      and "\001OLE" streams.\r
- *\r
- */\r
-HRESULT WINAPI OleConvertIStorageToOLESTREAM (\r
-    LPSTORAGE pstg,\r
-    LPOLESTREAM pOleStream)\r
-{\r
-    int i;\r
-    HRESULT hRes = S_OK;\r
-    IStream *pStream;\r
-    OLECONVERT_OLESTREAM_DATA pOleStreamData[2];\r
-    static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};\r
-\r
-\r
-    memset(pOleStreamData, 0, sizeof(pOleStreamData));\r
-\r
-    if(pstg == NULL || pOleStream == NULL)\r
-    {\r
-        hRes = E_INVALIDARG;\r
-    }\r
-    if(hRes == S_OK)\r
-    {\r
-        /* Get the ProgID */\r
-        pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;\r
-        hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));\r
-    }\r
-    if(hRes == S_OK)\r
-    {\r
-        /* Was it originally Ole10 */\r
-        hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);\r
-        if(hRes == S_OK)\r
-        {\r
-            IStream_Release(pStream);\r
-            /* Get Presentation Data for Ole10Native */\r
-            OLECONVERT_GetOle10PresData(pstg, pOleStreamData);\r
-        }\r
-        else\r
-        {\r
-            /* Get Presentation Data (OLE20) */\r
-            OLECONVERT_GetOle20PresData(pstg, pOleStreamData);\r
-        }\r
-\r
-        /* Save OLESTREAM */\r
-        hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);\r
-        if(hRes == S_OK)\r
-        {\r
-            hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);\r
-        }\r
-\r
-    }\r
-\r
-    /* Free allocated memory */\r
-    for(i=0; i < 2; i++)\r
-    {\r
-        HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);\r
-    }\r
-\r
-    return hRes;\r
-}\r
-\r
-/***********************************************************************\r
- *             GetConvertStg (OLE32.@)\r
- */\r
-HRESULT WINAPI GetConvertStg(IStorage *stg) {\r
-    FIXME("unimplemented stub!\n");\r
-    return E_FAIL;\r
-}\r
-\r
-/******************************************************************************\r
- * StgIsStorageFile [OLE32.@]\r
- */\r
-HRESULT WINAPI\r
-StgIsStorageFile(LPCOLESTR fn)\r
-{\r
-       HANDLE          hf;\r
-       BYTE            magic[8];\r
-       DWORD           bytes_read;\r
-\r
-       TRACE("(\'%s\')\n", debugstr_w(fn));\r
-       hf = CreateFileW(fn, GENERIC_READ,\r
-                        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,\r
-                        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);\r
-\r
-       if (hf == INVALID_HANDLE_VALUE)\r
-               return STG_E_FILENOTFOUND;\r
-\r
-       if (!ReadFile(hf, magic, 8, &bytes_read, NULL))\r
-       {\r
-               WARN(" unable to read file\n");\r
-               CloseHandle(hf);\r
-               return S_FALSE;\r
-       }\r
-\r
-       CloseHandle(hf);\r
-\r
-       if (bytes_read != 8) {\r
-               WARN(" too short\n");\r
-               return S_FALSE;\r
-       }\r
-\r
-       if (!memcmp(magic,STORAGE_magic,8)) {\r
-               WARN(" -> YES\n");\r
-               return S_OK;\r
-       }\r
-\r
-       WARN(" -> Invalid header.\n");\r
-       return S_FALSE;\r
-}\r
+/*
+ * Compound Storage (32 bit version)
+ * Storage implementation
+ *
+ * This file contains the compound file implementation
+ * of the storage interface.
+ *
+ * Copyright 1999 Francis Beaudet
+ * Copyright 1999 Sylvain St-Germain
+ * Copyright 1999 Thuy Nguyen
+ * Copyright 2005 Mike McCormack
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "winuser.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+#include "storage32.h"
+#include "ole2.h"      /* For Write/ReadClassStm */
+
+#include "winreg.h"
+#include "wine/wingdi16.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(storage);
+
+#define FILE_BEGIN 0
+
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+#define OLESTREAM_ID 0x501
+#define OLESTREAM_MAX_STR_LEN 255
+
+static const char rootPropertyName[] = "Root Entry";
+
+
+/* OLESTREAM memory structure to use for Get and Put Routines */
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+typedef struct
+{
+    DWORD dwOleID;
+    DWORD dwTypeID;
+    DWORD dwOleTypeNameLength;
+    CHAR  strOleTypeName[OLESTREAM_MAX_STR_LEN];
+    CHAR  *pstrOleObjFileName;
+    DWORD dwOleObjFileNameLength;
+    DWORD dwMetaFileWidth;
+    DWORD dwMetaFileHeight;
+    CHAR  strUnknown[8]; /* don't know what is this 8 byts information in OLE stream. */
+    DWORD dwDataLength;
+    BYTE *pData;
+}OLECONVERT_OLESTREAM_DATA;
+
+/* CompObj Stream structure */
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+typedef struct
+{
+    BYTE byUnknown1[12];
+    CLSID clsid;
+    DWORD dwCLSIDNameLength;
+    CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
+    DWORD dwOleTypeNameLength;
+    CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
+    DWORD dwProgIDNameLength;
+    CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
+    BYTE byUnknown2[16];
+}OLECONVERT_ISTORAGE_COMPOBJ;
+
+
+/* Ole Presention Stream structure */
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+typedef struct
+{
+    BYTE byUnknown1[28];
+    DWORD dwExtentX;
+    DWORD dwExtentY;
+    DWORD dwSize;
+    BYTE *pData;
+}OLECONVERT_ISTORAGE_OLEPRES;
+
+
+
+/***********************************************************************
+ * Forward declaration of internal functions used by the method DestroyElement
+ */
+static HRESULT deleteStorageProperty(
+  StorageImpl *parentStorage,
+  ULONG        foundPropertyIndexToDelete,
+  StgProperty  propertyToDelete);
+
+static HRESULT deleteStreamProperty(
+  StorageImpl *parentStorage,
+  ULONG         foundPropertyIndexToDelete,
+  StgProperty   propertyToDelete);
+
+static HRESULT findPlaceholder(
+  StorageImpl *storage,
+  ULONG         propertyIndexToStore,
+  ULONG         storagePropertyIndex,
+  INT         typeOfRelation);
+
+static HRESULT adjustPropertyChain(
+  StorageImpl *This,
+  StgProperty   propertyToDelete,
+  StgProperty   parentProperty,
+  ULONG         parentPropertyId,
+  INT         typeOfRelation);
+
+/***********************************************************************
+ * Declaration of the functions used to manipulate StgProperty
+ */
+
+static ULONG getFreeProperty(
+  StorageImpl *storage);
+
+static void updatePropertyChain(
+  StorageImpl *storage,
+  ULONG       newPropertyIndex,
+  StgProperty newProperty);
+
+static LONG propertyNameCmp(
+    const OLECHAR *newProperty,
+    const OLECHAR *currentProperty);
+
+
+/***********************************************************************
+ * Declaration of miscellaneous functions...
+ */
+static HRESULT validateSTGM(DWORD stgmValue);
+
+static DWORD GetShareModeFromSTGM(DWORD stgm);
+static DWORD GetAccessModeFromSTGM(DWORD stgm);
+static DWORD GetCreationModeFromSTGM(DWORD stgm);
+
+extern IPropertySetStorageVtbl IPropertySetStorage_Vtbl;
+
+
+
+/************************************************************************
+** Storage32BaseImpl implementatiion
+*/
+
+/************************************************************************
+ * Storage32BaseImpl_QueryInterface (IUnknown)
+ *
+ * This method implements the common QueryInterface for all IStorage32
+ * implementations contained in this file.
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+HRESULT WINAPI StorageBaseImpl_QueryInterface(
+  IStorage*        iface,
+  REFIID             riid,
+  void**             ppvObject)
+{
+  StorageBaseImpl *This = (StorageBaseImpl *)iface;
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppvObject==0) )
+    return E_INVALIDARG;
+
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
+  {
+    *ppvObject = (IStorage*)This;
+  }
+  else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
+  {
+    *ppvObject = (IStorage*)This;
+  }
+  else if (memcmp(&IID_IPropertySetStorage, riid, sizeof(IID_IPropertySetStorage)) == 0)
+  {
+    *ppvObject = (IStorage*)&This->pssVtbl;
+  }
+
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+    return E_NOINTERFACE;
+
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  IStorage_AddRef(iface);
+
+  return S_OK;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_AddRef (IUnknown)
+ *
+ * This method implements the common AddRef for all IStorage32
+ * implementations contained in this file.
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+ULONG WINAPI StorageBaseImpl_AddRef(
+            IStorage* iface)
+{
+  StorageBaseImpl *This = (StorageBaseImpl *)iface;
+  ULONG ref = InterlockedIncrement(&This->ref);
+
+  TRACE("(%p) AddRef to %ld\n", This, ref);
+
+  return ref;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_Release (IUnknown)
+ *
+ * This method implements the common Release for all IStorage32
+ * implementations contained in this file.
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+ULONG WINAPI StorageBaseImpl_Release(
+      IStorage* iface)
+{
+  StorageBaseImpl *This = (StorageBaseImpl *)iface;
+  /*
+   * Decrease the reference count on this object.
+   */
+  ULONG ref = InterlockedDecrement(&This->ref);
+
+  TRACE("(%p) ReleaseRef to %ld\n", This, ref);
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (ref == 0)
+  {
+    /*
+     * Since we are using a system of base-classes, we want to call the
+     * destructor of the appropriate derived class. To do this, we are
+     * using virtual functions to implement the destructor.
+     */
+    This->v_destructor(This);
+  }
+
+  return ref;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_OpenStream (IStorage)
+ *
+ * This method will open the specified stream object from the current storage.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_OpenStream(
+  IStorage*        iface,
+  const OLECHAR*   pwcsName,  /* [string][in] */
+  void*            reserved1, /* [unique][in] */
+  DWORD            grfMode,   /* [in]  */
+  DWORD            reserved2, /* [in]  */
+  IStream**        ppstm)     /* [out] */
+{
+  StorageBaseImpl *This = (StorageBaseImpl *)iface;
+  IEnumSTATSTGImpl* propertyEnumeration;
+  StgStreamImpl*    newStream;
+  StgProperty       currentProperty;
+  ULONG             foundPropertyIndex;
+  HRESULT           res = STG_E_UNKNOWN;
+  DWORD             parent_grfMode;
+
+  TRACE("(%p, %s, %p, %lx, %ld, %p)\n",
+       iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (pwcsName==NULL) || (ppstm==0) )
+  {
+    res = E_INVALIDARG;
+    goto end;
+  }
+
+  /*
+   * Initialize the out parameter
+   */
+  *ppstm = NULL;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+  {
+    res = STG_E_INVALIDFLAG;
+    goto end;
+  }
+
+  /*
+   * As documented.
+   */
+  if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||
+        (grfMode & STGM_DELETEONRELEASE) ||
+        (grfMode & STGM_TRANSACTED) )
+  {
+    res = STG_E_INVALIDFUNCTION;
+    goto end;
+  }
+
+  /*
+   * Check that we're compatible with the parent's storage mode
+   */
+  parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags );
+  if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) )
+  {
+    res = STG_E_ACCESSDENIED;
+    goto end;
+  }
+
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(
+    This->ancestorStorage,
+    This->rootPropertySetIndex);
+
+  /*
+   * Search the enumeration for the property with the given name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
+    propertyEnumeration,
+    pwcsName,
+    &currentProperty);
+
+  /*
+   * Delete the property enumeration since we don't need it anymore
+   */
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  /*
+   * If it was found, construct the stream object and return a pointer to it.
+   */
+  if ( (foundPropertyIndex!=PROPERTY_NULL) &&
+       (currentProperty.propertyType==PROPTYPE_STREAM) )
+  {
+    newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);
+
+    if (newStream!=0)
+    {
+      newStream->grfMode = grfMode;
+      *ppstm = (IStream*)newStream;
+
+      /*
+       * Since we are returning a pointer to the interface, we have to
+       * nail down the reference.
+       */
+      IStream_AddRef(*ppstm);
+
+      res = S_OK;
+      goto end;
+    }
+
+    res = E_OUTOFMEMORY;
+    goto end;
+  }
+
+  res = STG_E_FILENOTFOUND;
+
+end:
+  if (res == S_OK)
+    TRACE("<-- IStream %p\n", *ppstm);
+  TRACE("<-- %08lx\n", res);
+  return res;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_OpenStorage (IStorage)
+ *
+ * This method will open a new storage object from the current storage.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_OpenStorage(
+  IStorage*        iface,
+  const OLECHAR*   pwcsName,      /* [string][unique][in] */
+  IStorage*        pstgPriority,  /* [unique][in] */
+  DWORD            grfMode,       /* [in] */
+  SNB              snbExclude,    /* [unique][in] */
+  DWORD            reserved,      /* [in] */
+  IStorage**       ppstg)         /* [out] */
+{
+  StorageBaseImpl *This = (StorageBaseImpl *)iface;
+  StorageInternalImpl* newStorage;
+  IEnumSTATSTGImpl*      propertyEnumeration;
+  StgProperty            currentProperty;
+  ULONG                  foundPropertyIndex;
+  HRESULT                res = STG_E_UNKNOWN;
+  DWORD                  parent_grfMode;
+
+  TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",
+       iface, debugstr_w(pwcsName), pstgPriority,
+       grfMode, snbExclude, reserved, ppstg);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
+  {
+    res = E_INVALIDARG;
+    goto end;
+  }
+
+  /* as documented */
+  if (snbExclude != NULL)
+  {
+    res = STG_E_INVALIDPARAMETER;
+    goto end;
+  }
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+  {
+    res = STG_E_INVALIDFLAG;
+    goto end;
+  }
+
+  /*
+   * As documented.
+   */
+  if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||
+        (grfMode & STGM_DELETEONRELEASE) ||
+        (grfMode & STGM_PRIORITY) )
+  {
+    res = STG_E_INVALIDFUNCTION;
+    goto end;
+  }
+
+  /*
+   * Check that we're compatible with the parent's storage mode
+   */
+  parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags );
+  if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) )
+  {
+    res = STG_E_ACCESSDENIED;
+    goto end;
+  }
+
+  /*
+   * Initialize the out parameter
+   */
+  *ppstg = NULL;
+
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(
+                          This->ancestorStorage,
+                          This->rootPropertySetIndex);
+
+  /*
+   * Search the enumeration for the property with the given name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
+                         propertyEnumeration,
+                         pwcsName,
+                         &currentProperty);
+
+  /*
+   * Delete the property enumeration since we don't need it anymore
+   */
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  /*
+   * If it was found, construct the stream object and return a pointer to it.
+   */
+  if ( (foundPropertyIndex!=PROPERTY_NULL) &&
+       (currentProperty.propertyType==PROPTYPE_STORAGE) )
+  {
+    /*
+     * Construct a new Storage object
+     */
+    newStorage = StorageInternalImpl_Construct(
+                   This->ancestorStorage,
+                   grfMode,
+                   foundPropertyIndex);
+
+    if (newStorage != 0)
+    {
+      *ppstg = (IStorage*)newStorage;
+
+      /*
+       * Since we are returning a pointer to the interface,
+       * we have to nail down the reference.
+       */
+      StorageBaseImpl_AddRef(*ppstg);
+
+      res = S_OK;
+      goto end;
+    }
+
+    res = STG_E_INSUFFICIENTMEMORY;
+    goto end;
+  }
+
+  res = STG_E_FILENOTFOUND;
+
+end:
+  TRACE("<-- %08lx\n", res);
+  return res;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_EnumElements (IStorage)
+ *
+ * This method will create an enumerator object that can be used to
+ * retrieve informatino about all the properties in the storage object.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_EnumElements(
+  IStorage*       iface,
+  DWORD           reserved1, /* [in] */
+  void*           reserved2, /* [size_is][unique][in] */
+  DWORD           reserved3, /* [in] */
+  IEnumSTATSTG**  ppenum)    /* [out] */
+{
+  StorageBaseImpl *This = (StorageBaseImpl *)iface;
+  IEnumSTATSTGImpl* newEnum;
+
+  TRACE("(%p, %ld, %p, %ld, %p)\n",
+       iface, reserved1, reserved2, reserved3, ppenum);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppenum==0))
+    return E_INVALIDARG;
+
+  /*
+   * Construct the enumerator.
+   */
+  newEnum = IEnumSTATSTGImpl_Construct(
+              This->ancestorStorage,
+              This->rootPropertySetIndex);
+
+  if (newEnum!=0)
+  {
+    *ppenum = (IEnumSTATSTG*)newEnum;
+
+    /*
+     * Don't forget to nail down a reference to the new object before
+     * returning it.
+     */
+    IEnumSTATSTG_AddRef(*ppenum);
+
+    return S_OK;
+  }
+
+  return E_OUTOFMEMORY;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_Stat (IStorage)
+ *
+ * This method will retrieve information about this storage object.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_Stat(
+  IStorage*        iface,
+  STATSTG*         pstatstg,     /* [out] */
+  DWORD            grfStatFlag)  /* [in] */
+{
+  StorageBaseImpl *This = (StorageBaseImpl *)iface;
+  StgProperty    curProperty;
+  BOOL           readSuccessful;
+  HRESULT        res = STG_E_UNKNOWN;
+
+  TRACE("(%p, %p, %lx)\n",
+       iface, pstatstg, grfStatFlag);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (pstatstg==0))
+  {
+    res = E_INVALIDARG;
+    goto end;
+  }
+
+  /*
+   * Read the information from the property.
+   */
+  readSuccessful = StorageImpl_ReadProperty(
+                    This->ancestorStorage,
+                    This->rootPropertySetIndex,
+                    &curProperty);
+
+  if (readSuccessful)
+  {
+    StorageUtl_CopyPropertyToSTATSTG(
+      pstatstg,
+      &curProperty,
+      grfStatFlag);
+
+    res = S_OK;
+    goto end;
+  }
+
+  res = E_FAIL;
+
+end:
+  if (res == S_OK)
+  {
+    TRACE("<-- STATSTG: pwcsName: %s, type: %ld, cbSize.Low/High: %ld/%ld, grfMode: %08lx, grfLocksSupported: %ld, grfStateBits: %08lx\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);
+  }
+  TRACE("<-- %08lx\n", res);
+  return res;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_RenameElement (IStorage)
+ *
+ * This method will rename the specified element.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ *
+ * Implementation notes: The method used to rename consists of creating a clone
+ *    of the deleted StgProperty object setting it with the new name and to
+ *    perform a DestroyElement of the old StgProperty.
+ */
+HRESULT WINAPI StorageBaseImpl_RenameElement(
+            IStorage*        iface,
+            const OLECHAR*   pwcsOldName,  /* [in] */
+            const OLECHAR*   pwcsNewName)  /* [in] */
+{
+  StorageBaseImpl *This = (StorageBaseImpl *)iface;
+  IEnumSTATSTGImpl* propertyEnumeration;
+  StgProperty       currentProperty;
+  ULONG             foundPropertyIndex;
+
+  TRACE("(%p, %s, %s)\n",
+       iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
+
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
+                                                   This->rootPropertySetIndex);
+
+  /*
+   * Search the enumeration for the new property name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsNewName,
+                                                     &currentProperty);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    /*
+     * There is already a property with the new name
+     */
+    IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+    return STG_E_FILEALREADYEXISTS;
+  }
+
+  IEnumSTATSTG_Reset((IEnumSTATSTG*)propertyEnumeration);
+
+  /*
+   * Search the enumeration for the old property name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsOldName,
+                                                     &currentProperty);
+
+  /*
+   * Delete the property enumeration since we don't need it anymore
+   */
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    StgProperty renamedProperty;
+    ULONG       renamedPropertyIndex;
+
+    /*
+     * Setup a new property for the renamed property
+     */
+    renamedProperty.sizeOfNameString =
+      ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
+
+    if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+      return STG_E_INVALIDNAME;
+
+    strcpyW(renamedProperty.name, pwcsNewName);
+
+    renamedProperty.propertyType  = currentProperty.propertyType;
+    renamedProperty.startingBlock = currentProperty.startingBlock;
+    renamedProperty.size.u.LowPart  = currentProperty.size.u.LowPart;
+    renamedProperty.size.u.HighPart = currentProperty.size.u.HighPart;
+
+    renamedProperty.previousProperty = PROPERTY_NULL;
+    renamedProperty.nextProperty     = PROPERTY_NULL;
+
+    /*
+     * Bring the dirProperty link in case it is a storage and in which
+     * case the renamed storage elements don't require to be reorganized.
+     */
+    renamedProperty.dirProperty = currentProperty.dirProperty;
+
+    /* call CoFileTime to get the current time
+    renamedProperty.timeStampS1
+    renamedProperty.timeStampD1
+    renamedProperty.timeStampS2
+    renamedProperty.timeStampD2
+    renamedProperty.propertyUniqueID
+    */
+
+    /*
+     * Obtain a free property in the property chain
+     */
+    renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
+
+    /*
+     * Save the new property into the new property spot
+     */
+    StorageImpl_WriteProperty(
+      This->ancestorStorage,
+      renamedPropertyIndex,
+      &renamedProperty);
+
+    /*
+     * Find a spot in the property chain for our newly created property.
+     */
+    updatePropertyChain(
+      (StorageImpl*)This,
+      renamedPropertyIndex,
+      renamedProperty);
+
+    /*
+     * At this point the renamed property has been inserted in the tree,
+     * now, before to Destroy the old property we must zeroed it's dirProperty
+     * otherwise the DestroyProperty below will zap it all and we do not want
+     * this to happen.
+     * Also, we fake that the old property is a storage so the DestroyProperty
+     * will not do a SetSize(0) on the stream data.
+     *
+     * This means that we need to tweek the StgProperty if it is a stream or a
+     * non empty storage.
+     */
+    StorageImpl_ReadProperty(This->ancestorStorage,
+                             foundPropertyIndex,
+                             &currentProperty);
+
+    currentProperty.dirProperty  = PROPERTY_NULL;
+    currentProperty.propertyType = PROPTYPE_STORAGE;
+    StorageImpl_WriteProperty(
+      This->ancestorStorage,
+      foundPropertyIndex,
+      &currentProperty);
+
+    /*
+     * Invoke Destroy to get rid of the ole property and automatically redo
+     * the linking of it's previous and next members...
+     */
+    IStorage_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
+
+  }
+  else
+  {
+    /*
+     * There is no property with the old name
+     */
+    return STG_E_FILENOTFOUND;
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_CreateStream (IStorage)
+ *
+ * This method will create a stream object within this storage
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_CreateStream(
+            IStorage*        iface,
+            const OLECHAR*   pwcsName,  /* [string][in] */
+            DWORD            grfMode,   /* [in] */
+            DWORD            reserved1, /* [in] */
+            DWORD            reserved2, /* [in] */
+            IStream**        ppstm)     /* [out] */
+{
+  StorageBaseImpl *This = (StorageBaseImpl *)iface;
+  IEnumSTATSTGImpl* propertyEnumeration;
+  StgStreamImpl*    newStream;
+  StgProperty       currentProperty, newStreamProperty;
+  ULONG             foundPropertyIndex, newPropertyIndex;
+  DWORD             parent_grfMode;
+
+  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
+       iface, debugstr_w(pwcsName), grfMode,
+       reserved1, reserved2, ppstm);
+
+  /*
+   * Validate parameters
+   */
+  if (ppstm == 0)
+    return STG_E_INVALIDPOINTER;
+
+  if (pwcsName == 0)
+    return STG_E_INVALIDNAME;
+
+  if (reserved1 || reserved2)
+    return STG_E_INVALIDPARAMETER;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) 
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * As documented.
+   */
+  if ((grfMode & STGM_DELETEONRELEASE) ||
+      (grfMode & STGM_TRANSACTED))
+    return STG_E_INVALIDFUNCTION;
+
+  /*
+   * Check that we're compatible with the parent's storage mode
+   */
+  parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags );
+  if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) )
+    return STG_E_ACCESSDENIED;
+
+  /*
+   * Initialize the out parameter
+   */
+  *ppstm = 0;
+
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
+                                                   This->rootPropertySetIndex);
+
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsName,
+                                                     &currentProperty);
+
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    /*
+     * An element with this name already exists
+     */
+    if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
+    {
+      IStorage_DestroyElement(iface, pwcsName);
+    }
+    else
+      return STG_E_FILEALREADYEXISTS;
+  }
+
+  /*
+   * memset the empty property
+   */
+  memset(&newStreamProperty, 0, sizeof(StgProperty));
+
+  newStreamProperty.sizeOfNameString =
+      ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
+
+  if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+    return STG_E_INVALIDNAME;
+
+  strcpyW(newStreamProperty.name, pwcsName);
+
+  newStreamProperty.propertyType  = PROPTYPE_STREAM;
+  newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
+  newStreamProperty.size.u.LowPart  = 0;
+  newStreamProperty.size.u.HighPart = 0;
+
+  newStreamProperty.previousProperty = PROPERTY_NULL;
+  newStreamProperty.nextProperty     = PROPERTY_NULL;
+  newStreamProperty.dirProperty      = PROPERTY_NULL;
+
+  /* call CoFileTime to get the current time
+  newStreamProperty.timeStampS1
+  newStreamProperty.timeStampD1
+  newStreamProperty.timeStampS2
+  newStreamProperty.timeStampD2
+  */
+
+  /*  newStreamProperty.propertyUniqueID */
+
+  /*
+   * Get a free property or create a new one
+   */
+  newPropertyIndex = getFreeProperty(This->ancestorStorage);
+
+  /*
+   * Save the new property into the new property spot
+   */
+  StorageImpl_WriteProperty(
+    This->ancestorStorage,
+    newPropertyIndex,
+    &newStreamProperty);
+
+  /*
+   * Find a spot in the property chain for our newly created property.
+   */
+  updatePropertyChain(
+    (StorageImpl*)This,
+    newPropertyIndex,
+    newStreamProperty);
+
+  /*
+   * Open the stream to return it.
+   */
+  newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);
+
+  if (newStream != 0)
+  {
+    *ppstm = (IStream*)newStream;
+
+    /*
+     * Since we are returning a pointer to the interface, we have to nail down
+     * the reference.
+     */
+    IStream_AddRef(*ppstm);
+  }
+  else
+  {
+    return STG_E_INSUFFICIENTMEMORY;
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_SetClass (IStorage)
+ *
+ * This method will write the specified CLSID in the property of this
+ * storage.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_SetClass(
+  IStorage*        iface,
+  REFCLSID         clsid) /* [in] */
+{
+  StorageBaseImpl *This = (StorageBaseImpl *)iface;
+  HRESULT hRes = E_FAIL;
+  StgProperty curProperty;
+  BOOL success;
+
+  TRACE("(%p, %p)\n", iface, clsid);
+
+  success = StorageImpl_ReadProperty(This->ancestorStorage,
+                                       This->rootPropertySetIndex,
+                                       &curProperty);
+  if (success)
+  {
+    curProperty.propertyUniqueID = *clsid;
+
+    success =  StorageImpl_WriteProperty(This->ancestorStorage,
+                                           This->rootPropertySetIndex,
+                                           &curProperty);
+    if (success)
+      hRes = S_OK;
+  }
+
+  return hRes;
+}
+
+/************************************************************************
+** Storage32Impl implementation
+*/
+
+/************************************************************************
+ * Storage32Impl_CreateStorage (IStorage)
+ *
+ * This method will create the storage object within the provided storage.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageImpl_CreateStorage(
+  IStorage*      iface,
+  const OLECHAR  *pwcsName, /* [string][in] */
+  DWORD            grfMode,   /* [in] */
+  DWORD            reserved1, /* [in] */
+  DWORD            reserved2, /* [in] */
+  IStorage       **ppstg)   /* [out] */
+{
+  StorageImpl* const This=(StorageImpl*)iface;
+
+  IEnumSTATSTGImpl *propertyEnumeration;
+  StgProperty      currentProperty;
+  StgProperty      newProperty;
+  ULONG            foundPropertyIndex;
+  ULONG            newPropertyIndex;
+  HRESULT          hr;
+  DWORD            parent_grfMode;
+
+  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
+       iface, debugstr_w(pwcsName), grfMode,
+       reserved1, reserved2, ppstg);
+
+  /*
+   * Validate parameters
+   */
+  if (ppstg == 0)
+    return STG_E_INVALIDPOINTER;
+
+  if (pwcsName == 0)
+    return STG_E_INVALIDNAME;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ) ||
+       (grfMode & STGM_DELETEONRELEASE) )
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * Check that we're compatible with the parent's storage mode
+   */
+  parent_grfMode = STGM_ACCESS_MODE( This->base.ancestorStorage->base.openFlags );
+  if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) )
+    return STG_E_ACCESSDENIED;
+
+  /*
+   * Initialize the out parameter
+   */
+  *ppstg = 0;
+
+  /*
+   * Create a property enumeration and search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct( This->base.ancestorStorage,
+                                                    This->base.rootPropertySetIndex);
+
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsName,
+                                                     &currentProperty);
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    /*
+     * An element with this name already exists
+     */
+    if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
+      IStorage_DestroyElement(iface, pwcsName);
+    else
+      return STG_E_FILEALREADYEXISTS;
+  }
+
+  /*
+   * memset the empty property
+   */
+  memset(&newProperty, 0, sizeof(StgProperty));
+
+  newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
+
+  if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+    return STG_E_INVALIDNAME;
+
+  strcpyW(newProperty.name, pwcsName);
+
+  newProperty.propertyType  = PROPTYPE_STORAGE;
+  newProperty.startingBlock = BLOCK_END_OF_CHAIN;
+  newProperty.size.u.LowPart  = 0;
+  newProperty.size.u.HighPart = 0;
+
+  newProperty.previousProperty = PROPERTY_NULL;
+  newProperty.nextProperty     = PROPERTY_NULL;
+  newProperty.dirProperty      = PROPERTY_NULL;
+
+  /* call CoFileTime to get the current time
+  newProperty.timeStampS1
+  newProperty.timeStampD1
+  newProperty.timeStampS2
+  newProperty.timeStampD2
+  */
+
+  /*  newStorageProperty.propertyUniqueID */
+
+  /*
+   * Obtain a free property in the property chain
+   */
+  newPropertyIndex = getFreeProperty(This->base.ancestorStorage);
+
+  /*
+   * Save the new property into the new property spot
+   */
+  StorageImpl_WriteProperty(
+    This->base.ancestorStorage,
+    newPropertyIndex,
+    &newProperty);
+
+  /*
+   * Find a spot in the property chain for our newly created property.
+   */
+  updatePropertyChain(
+    This,
+    newPropertyIndex,
+    newProperty);
+
+  /*
+   * Open it to get a pointer to return.
+   */
+  hr = IStorage_OpenStorage(
+         iface,
+         (const OLECHAR*)pwcsName,
+         0,
+         grfMode,
+         0,
+         0,
+         ppstg);
+
+  if( (hr != S_OK) || (*ppstg == NULL))
+  {
+    return hr;
+  }
+
+
+  return S_OK;
+}
+
+
+/***************************************************************************
+ *
+ * Internal Method
+ *
+ * Get a free property or create a new one.
+ */
+static ULONG getFreeProperty(
+  StorageImpl *storage)
+{
+  ULONG       currentPropertyIndex = 0;
+  ULONG       newPropertyIndex     = PROPERTY_NULL;
+  BOOL      readSuccessful        = TRUE;
+  StgProperty currentProperty;
+
+  do
+  {
+    /*
+     * Start by reading the root property
+     */
+    readSuccessful = StorageImpl_ReadProperty(storage->base.ancestorStorage,
+                                               currentPropertyIndex,
+                                               &currentProperty);
+    if (readSuccessful)
+    {
+      if (currentProperty.sizeOfNameString == 0)
+      {
+        /*
+         * The property existis and is available, we found it.
+         */
+        newPropertyIndex = currentPropertyIndex;
+      }
+    }
+    else
+    {
+      /*
+       * We exhausted the property list, we will create more space below
+       */
+      newPropertyIndex = currentPropertyIndex;
+    }
+    currentPropertyIndex++;
+
+  } while (newPropertyIndex == PROPERTY_NULL);
+
+  /*
+   * grow the property chain
+   */
+  if (! readSuccessful)
+  {
+    StgProperty    emptyProperty;
+    ULARGE_INTEGER newSize;
+    ULONG          propertyIndex;
+    ULONG          lastProperty  = 0;
+    ULONG          blockCount    = 0;
+
+    /*
+     * obtain the new count of property blocks
+     */
+    blockCount = BlockChainStream_GetCount(
+                   storage->base.ancestorStorage->rootBlockChain)+1;
+
+    /*
+     * initialize the size used by the property stream
+     */
+    newSize.u.HighPart = 0;
+    newSize.u.LowPart  = storage->bigBlockSize * blockCount;
+
+    /*
+     * add a property block to the property chain
+     */
+    BlockChainStream_SetSize(storage->base.ancestorStorage->rootBlockChain, newSize);
+
+    /*
+     * memset the empty property in order to initialize the unused newly
+     * created property
+     */
+    memset(&emptyProperty, 0, sizeof(StgProperty));
+
+    /*
+     * initialize them
+     */
+    lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
+
+    for(
+      propertyIndex = newPropertyIndex;
+      propertyIndex < lastProperty;
+      propertyIndex++)
+    {
+      StorageImpl_WriteProperty(
+        storage->base.ancestorStorage,
+        propertyIndex,
+        &emptyProperty);
+    }
+  }
+
+  return newPropertyIndex;
+}
+
+/****************************************************************************
+ *
+ * Internal Method
+ *
+ * Case insensitive comparaison of StgProperty.name by first considering
+ * their size.
+ *
+ * Returns <0 when newPrpoerty < currentProperty
+ *         >0 when newPrpoerty > currentProperty
+ *          0 when newPrpoerty == currentProperty
+ */
+static LONG propertyNameCmp(
+    const OLECHAR *newProperty,
+    const OLECHAR *currentProperty)
+{
+  LONG diff      = lstrlenW(newProperty) - lstrlenW(currentProperty);
+
+  if (diff == 0)
+  {
+    /*
+     * We compare the string themselves only when they are of the same length
+     */
+    diff = lstrcmpiW( newProperty, currentProperty);
+  }
+
+  return diff;
+}
+
+/****************************************************************************
+ *
+ * Internal Method
+ *
+ * Properly link this new element in the property chain.
+ */
+static void updatePropertyChain(
+  StorageImpl *storage,
+  ULONG         newPropertyIndex,
+  StgProperty   newProperty)
+{
+  StgProperty currentProperty;
+
+  /*
+   * Read the root property
+   */
+  StorageImpl_ReadProperty(storage->base.ancestorStorage,
+                             storage->base.rootPropertySetIndex,
+                             &currentProperty);
+
+  if (currentProperty.dirProperty != PROPERTY_NULL)
+  {
+    /*
+     * The root storage contains some element, therefore, start the research
+     * for the appropriate location.
+     */
+    BOOL found = 0;
+    ULONG  current, next, previous, currentPropertyId;
+
+    /*
+     * Keep the StgProperty sequence number of the storage first property
+     */
+    currentPropertyId = currentProperty.dirProperty;
+
+    /*
+     * Read
+     */
+    StorageImpl_ReadProperty(storage->base.ancestorStorage,
+                               currentProperty.dirProperty,
+                               &currentProperty);
+
+    previous = currentProperty.previousProperty;
+    next     = currentProperty.nextProperty;
+    current  = currentPropertyId;
+
+    while (found == 0)
+    {
+      LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
+
+      if (diff < 0)
+      {
+        if (previous != PROPERTY_NULL)
+        {
+          StorageImpl_ReadProperty(storage->base.ancestorStorage,
+                                     previous,
+                                     &currentProperty);
+          current = previous;
+        }
+        else
+        {
+          currentProperty.previousProperty = newPropertyIndex;
+          StorageImpl_WriteProperty(storage->base.ancestorStorage,
+                                      current,
+                                      &currentProperty);
+          found = 1;
+        }
+      }
+      else if (diff > 0)
+      {
+        if (next != PROPERTY_NULL)
+        {
+          StorageImpl_ReadProperty(storage->base.ancestorStorage,
+                                     next,
+                                     &currentProperty);
+          current = next;
+        }
+        else
+        {
+          currentProperty.nextProperty = newPropertyIndex;
+          StorageImpl_WriteProperty(storage->base.ancestorStorage,
+                                      current,
+                                      &currentProperty);
+          found = 1;
+        }
+      }
+      else
+      {
+       /*
+        * Trying to insert an item with the same name in the
+        * subtree structure.
+        */
+       assert(FALSE);
+      }
+
+      previous = currentProperty.previousProperty;
+      next     = currentProperty.nextProperty;
+    }
+  }
+  else
+  {
+    /*
+     * The root storage is empty, link the new property to it's dir property
+     */
+    currentProperty.dirProperty = newPropertyIndex;
+    StorageImpl_WriteProperty(storage->base.ancestorStorage,
+                                storage->base.rootPropertySetIndex,
+                                &currentProperty);
+  }
+}
+
+
+/*************************************************************************
+ * CopyTo (IStorage)
+ */
+HRESULT WINAPI StorageImpl_CopyTo(
+  IStorage*   iface,
+  DWORD       ciidExclude,  /* [in] */
+  const IID*  rgiidExclude, /* [size_is][unique][in] */
+  SNB         snbExclude,   /* [unique][in] */
+  IStorage*   pstgDest)     /* [unique][in] */
+{
+  IEnumSTATSTG *elements     = 0;
+  STATSTG      curElement, strStat;
+  HRESULT      hr;
+  IStorage     *pstgTmp, *pstgChild;
+  IStream      *pstrTmp, *pstrChild;
+
+  if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
+    FIXME("Exclude option not implemented\n");
+
+  TRACE("(%p, %ld, %p, %p, %p)\n",
+       iface, ciidExclude, rgiidExclude,
+       snbExclude, pstgDest);
+
+  /*
+   * Perform a sanity check
+   */
+  if ( pstgDest == 0 )
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Enumerate the elements
+   */
+  hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
+
+  if ( hr != S_OK )
+    return hr;
+
+  /*
+   * set the class ID
+   */
+  IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
+  IStorage_SetClass( pstgDest, &curElement.clsid );
+
+  do
+  {
+    /*
+     * Obtain the next element
+     */
+    hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
+
+    if ( hr == S_FALSE )
+    {
+      hr = S_OK;   /* done, every element has been copied */
+      break;
+    }
+
+    if (curElement.type == STGTY_STORAGE)
+    {
+      /*
+       * open child source storage
+       */
+      hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
+                                STGM_READ|STGM_SHARE_EXCLUSIVE,
+                                NULL, 0, &pstgChild );
+
+      if (hr != S_OK)
+        break;
+
+      /*
+       * Check if destination storage is not a child of the source
+       * storage, which will cause an infinite loop
+       */
+      if (pstgChild == pstgDest)
+      {
+       IEnumSTATSTG_Release(elements);
+
+       return STG_E_ACCESSDENIED;
+      }
+
+      /*
+       * create a new storage in destination storage
+       */
+      hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
+                                   STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
+                                  0, 0,
+                                   &pstgTmp );
+      /*
+       * if it already exist, don't create a new one use this one
+       */
+      if (hr == STG_E_FILEALREADYEXISTS)
+      {
+        hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
+                                   STGM_WRITE|STGM_SHARE_EXCLUSIVE,
+                                   NULL, 0, &pstgTmp );
+      }
+
+      if (hr != S_OK)
+        break;
+
+
+      /*
+       * do the copy recursively
+       */
+      hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
+                               snbExclude, pstgTmp );
+
+      IStorage_Release( pstgTmp );
+      IStorage_Release( pstgChild );
+    }
+    else if (curElement.type == STGTY_STREAM)
+    {
+      /*
+       * create a new stream in destination storage. If the stream already
+       * exist, it will be deleted and a new one will be created.
+       */
+      hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
+                                  STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
+                                  0, 0, &pstrTmp );
+
+      if (hr != S_OK)
+        break;
+
+      /*
+       * open child stream storage
+       */
+      hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
+                               STGM_READ|STGM_SHARE_EXCLUSIVE,
+                               0, &pstrChild );
+
+      if (hr != S_OK)
+        break;
+
+      /*
+       * Get the size of the source stream
+       */
+      IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
+
+      /*
+       * Set the size of the destination stream.
+       */
+      IStream_SetSize(pstrTmp, strStat.cbSize);
+
+      /*
+       * do the copy
+       */
+      hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
+                           NULL, NULL );
+
+      IStream_Release( pstrTmp );
+      IStream_Release( pstrChild );
+    }
+    else
+    {
+      WARN("unknown element type: %ld\n", curElement.type);
+    }
+
+  } while (hr == S_OK);
+
+  /*
+   * Clean-up
+   */
+  IEnumSTATSTG_Release(elements);
+
+  return hr;
+}
+
+/*************************************************************************
+ * MoveElementTo (IStorage)
+ */
+HRESULT WINAPI StorageImpl_MoveElementTo(
+  IStorage*     iface,
+  const OLECHAR *pwcsName,   /* [string][in] */
+  IStorage      *pstgDest,   /* [unique][in] */
+  const OLECHAR *pwcsNewName,/* [string][in] */
+  DWORD           grfFlags)    /* [in] */
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+/*************************************************************************
+ * Commit (IStorage)
+ */
+HRESULT WINAPI StorageImpl_Commit(
+  IStorage*   iface,
+  DWORD         grfCommitFlags)/* [in] */
+{
+  FIXME("(%ld): stub!\n", grfCommitFlags);
+  return S_OK;
+}
+
+/*************************************************************************
+ * Revert (IStorage)
+ */
+HRESULT WINAPI StorageImpl_Revert(
+  IStorage* iface)
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+/*************************************************************************
+ * DestroyElement (IStorage)
+ *
+ * Stategy: This implementation is build this way for simplicity not for speed.
+ *          I always delete the top most element of the enumeration and adjust
+ *          the deleted element pointer all the time.  This takes longer to
+ *          do but allow to reinvoke DestroyElement whenever we encounter a
+ *          storage object.  The optimisation reside in the usage of another
+ *          enumeration stategy that would give all the leaves of a storage
+ *          first. (postfix order)
+ */
+HRESULT WINAPI StorageImpl_DestroyElement(
+  IStorage*     iface,
+  const OLECHAR *pwcsName)/* [string][in] */
+{
+  StorageImpl* const This=(StorageImpl*)iface;
+
+  IEnumSTATSTGImpl* propertyEnumeration;
+  HRESULT           hr = S_OK;
+  BOOL            res;
+  StgProperty       propertyToDelete;
+  StgProperty       parentProperty;
+  ULONG             foundPropertyIndexToDelete;
+  ULONG             typeOfRelation;
+  ULONG             parentPropertyId;
+
+  TRACE("(%p, %s)\n",
+       iface, debugstr_w(pwcsName));
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (pwcsName==NULL)
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Create a property enumeration to search the property with the given name
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(
+    This->base.ancestorStorage,
+    This->base.rootPropertySetIndex);
+
+  foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
+    propertyEnumeration,
+    pwcsName,
+    &propertyToDelete);
+
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if ( foundPropertyIndexToDelete == PROPERTY_NULL )
+  {
+    return STG_E_FILENOTFOUND;
+  }
+
+  /*
+   * Find the parent property of the property to delete (the one that
+   * link to it).  If This->dirProperty == foundPropertyIndexToDelete,
+   * the parent is This. Otherwise, the parent is one of it's sibling...
+   */
+
+  /*
+   * First, read This's StgProperty..
+   */
+  res = StorageImpl_ReadProperty(
+          This->base.ancestorStorage,
+          This->base.rootPropertySetIndex,
+          &parentProperty);
+
+  assert(res);
+
+  /*
+   * Second, check to see if by any chance the actual storage (This) is not
+   * the parent of the property to delete... We never know...
+   */
+  if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
+  {
+    /*
+     * Set data as it would have been done in the else part...
+     */
+    typeOfRelation   = PROPERTY_RELATION_DIR;
+    parentPropertyId = This->base.rootPropertySetIndex;
+  }
+  else
+  {
+    /*
+     * Create a property enumeration to search the parent properties, and
+     * delete it once done.
+     */
+    IEnumSTATSTGImpl* propertyEnumeration2;
+
+    propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
+      This->base.ancestorStorage,
+      This->base.rootPropertySetIndex);
+
+    typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
+      propertyEnumeration2,
+      foundPropertyIndexToDelete,
+      &parentProperty,
+      &parentPropertyId);
+
+    IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
+  }
+
+  if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
+  {
+    hr = deleteStorageProperty(
+           This,
+           foundPropertyIndexToDelete,
+           propertyToDelete);
+  }
+  else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
+  {
+    hr = deleteStreamProperty(
+           This,
+           foundPropertyIndexToDelete,
+           propertyToDelete);
+  }
+
+  if (hr!=S_OK)
+    return hr;
+
+  /*
+   * Adjust the property chain
+   */
+  hr = adjustPropertyChain(
+        This,
+        propertyToDelete,
+        parentProperty,
+        parentPropertyId,
+        typeOfRelation);
+
+  return hr;
+}
+
+
+/************************************************************************
+ * StorageImpl_Stat (IStorage)
+ *
+ * This method will retrieve information about this storage object.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageImpl_Stat( IStorage* iface,
+                                 STATSTG*  pstatstg,     /* [out] */
+                                 DWORD     grfStatFlag)  /* [in] */
+{
+  StorageImpl* const This = (StorageImpl*)iface;
+  HRESULT result = StorageBaseImpl_Stat( iface, pstatstg, grfStatFlag );
+
+  if ( !FAILED(result) && ((grfStatFlag & STATFLAG_NONAME) == 0) && This->pwcsName )
+  {
+      CoTaskMemFree(pstatstg->pwcsName);
+      pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));
+      strcpyW(pstatstg->pwcsName, This->pwcsName);
+  }
+
+  return result;
+}
+
+
+
+/*********************************************************************
+ *
+ * Internal Method
+ *
+ * Perform the deletion of a complete storage node
+ *
+ */
+static HRESULT deleteStorageProperty(
+  StorageImpl *parentStorage,
+  ULONG        indexOfPropertyToDelete,
+  StgProperty  propertyToDelete)
+{
+  IEnumSTATSTG *elements     = 0;
+  IStorage   *childStorage = 0;
+  STATSTG      currentElement;
+  HRESULT      hr;
+  HRESULT      destroyHr = S_OK;
+
+  /*
+   * Open the storage and enumerate it
+   */
+  hr = StorageBaseImpl_OpenStorage(
+        (IStorage*)parentStorage,
+        propertyToDelete.name,
+        0,
+        STGM_SHARE_EXCLUSIVE,
+        0,
+        0,
+        &childStorage);
+
+  if (hr != S_OK)
+  {
+    return hr;
+  }
+
+  /*
+   * Enumerate the elements
+   */
+  IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
+
+  do
+  {
+    /*
+     * Obtain the next element
+     */
+    hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
+    if (hr==S_OK)
+    {
+      destroyHr = StorageImpl_DestroyElement(
+                    (IStorage*)childStorage,
+                    (OLECHAR*)currentElement.pwcsName);
+
+      CoTaskMemFree(currentElement.pwcsName);
+    }
+
+    /*
+     * We need to Reset the enumeration every time because we delete elements
+     * and the enumeration could be invalid
+     */
+    IEnumSTATSTG_Reset(elements);
+
+  } while ((hr == S_OK) && (destroyHr == S_OK));
+
+  /*
+   * Invalidate the property by zeroing it's name member.
+   */
+  propertyToDelete.sizeOfNameString = 0;
+
+  StorageImpl_WriteProperty(parentStorage->base.ancestorStorage,
+                            indexOfPropertyToDelete,
+                            &propertyToDelete);
+
+  IStorage_Release(childStorage);
+  IEnumSTATSTG_Release(elements);
+
+  return destroyHr;
+}
+
+/*********************************************************************
+ *
+ * Internal Method
+ *
+ * Perform the deletion of a stream node
+ *
+ */
+static HRESULT deleteStreamProperty(
+  StorageImpl *parentStorage,
+  ULONG         indexOfPropertyToDelete,
+  StgProperty   propertyToDelete)
+{
+  IStream      *pis;
+  HRESULT        hr;
+  ULARGE_INTEGER size;
+
+  size.u.HighPart = 0;
+  size.u.LowPart = 0;
+
+  hr = StorageBaseImpl_OpenStream(
+         (IStorage*)parentStorage,
+         (OLECHAR*)propertyToDelete.name,
+         NULL,
+         STGM_WRITE | STGM_SHARE_EXCLUSIVE,
+         0,
+         &pis);
+
+  if (hr!=S_OK)
+  {
+    return(hr);
+  }
+
+  /*
+   * Zap the stream
+   */
+  hr = IStream_SetSize(pis, size);
+
+  if(hr != S_OK)
+  {
+    return hr;
+  }
+
+  /*
+   * Release the stream object.
+   */
+  IStream_Release(pis);
+
+  /*
+   * Invalidate the property by zeroing it's name member.
+   */
+  propertyToDelete.sizeOfNameString = 0;
+
+  /*
+   * Here we should re-read the property so we get the updated pointer
+   * but since we are here to zap it, I don't do it...
+   */
+  StorageImpl_WriteProperty(
+    parentStorage->base.ancestorStorage,
+    indexOfPropertyToDelete,
+    &propertyToDelete);
+
+  return S_OK;
+}
+
+/*********************************************************************
+ *
+ * Internal Method
+ *
+ * Finds a placeholder for the StgProperty within the Storage
+ *
+ */
+static HRESULT findPlaceholder(
+  StorageImpl *storage,
+  ULONG         propertyIndexToStore,
+  ULONG         storePropertyIndex,
+  INT         typeOfRelation)
+{
+  StgProperty storeProperty;
+  HRESULT     hr = S_OK;
+  BOOL      res = TRUE;
+
+  /*
+   * Read the storage property
+   */
+  res = StorageImpl_ReadProperty(
+          storage->base.ancestorStorage,
+          storePropertyIndex,
+          &storeProperty);
+
+  if(! res)
+  {
+    return E_FAIL;
+  }
+
+  if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
+  {
+    if (storeProperty.previousProperty != PROPERTY_NULL)
+    {
+      return findPlaceholder(
+               storage,
+               propertyIndexToStore,
+               storeProperty.previousProperty,
+               typeOfRelation);
+    }
+    else
+    {
+      storeProperty.previousProperty = propertyIndexToStore;
+    }
+  }
+  else if (typeOfRelation == PROPERTY_RELATION_NEXT)
+  {
+    if (storeProperty.nextProperty != PROPERTY_NULL)
+    {
+      return findPlaceholder(
+               storage,
+               propertyIndexToStore,
+               storeProperty.nextProperty,
+               typeOfRelation);
+    }
+    else
+    {
+      storeProperty.nextProperty = propertyIndexToStore;
+    }
+  }
+  else if (typeOfRelation == PROPERTY_RELATION_DIR)
+  {
+    if (storeProperty.dirProperty != PROPERTY_NULL)
+    {
+      return findPlaceholder(
+               storage,
+               propertyIndexToStore,
+               storeProperty.dirProperty,
+               typeOfRelation);
+    }
+    else
+    {
+      storeProperty.dirProperty = propertyIndexToStore;
+    }
+  }
+
+  hr = StorageImpl_WriteProperty(
+         storage->base.ancestorStorage,
+         storePropertyIndex,
+         &storeProperty);
+
+  if(! hr)
+  {
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+/*************************************************************************
+ *
+ * Internal Method
+ *
+ * This method takes the previous and the next property link of a property
+ * to be deleted and find them a place in the Storage.
+ */
+static HRESULT adjustPropertyChain(
+  StorageImpl *This,
+  StgProperty   propertyToDelete,
+  StgProperty   parentProperty,
+  ULONG         parentPropertyId,
+  INT         typeOfRelation)
+{
+  ULONG   newLinkProperty        = PROPERTY_NULL;
+  BOOL  needToFindAPlaceholder = FALSE;
+  ULONG   storeNode              = PROPERTY_NULL;
+  ULONG   toStoreNode            = PROPERTY_NULL;
+  INT   relationType           = 0;
+  HRESULT hr                     = S_OK;
+  BOOL  res                    = TRUE;
+
+  if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
+  {
+    if (propertyToDelete.previousProperty != PROPERTY_NULL)
+    {
+      /*
+       * Set the parent previous to the property to delete previous
+       */
+      newLinkProperty = propertyToDelete.previousProperty;
+
+      if (propertyToDelete.nextProperty != PROPERTY_NULL)
+      {
+        /*
+         * We also need to find a storage for the other link, setup variables
+         * to do this at the end...
+         */
+        needToFindAPlaceholder = TRUE;
+        storeNode              = propertyToDelete.previousProperty;
+        toStoreNode            = propertyToDelete.nextProperty;
+        relationType           = PROPERTY_RELATION_NEXT;
+      }
+    }
+    else if (propertyToDelete.nextProperty != PROPERTY_NULL)
+    {
+      /*
+       * Set the parent previous to the property to delete next
+       */
+      newLinkProperty = propertyToDelete.nextProperty;
+    }
+
+    /*
+     * Link it for real...
+     */
+    parentProperty.previousProperty = newLinkProperty;
+
+  }
+  else if (typeOfRelation == PROPERTY_RELATION_NEXT)
+  {
+    if (propertyToDelete.previousProperty != PROPERTY_NULL)
+    {
+      /*
+       * Set the parent next to the property to delete next previous
+       */
+      newLinkProperty = propertyToDelete.previousProperty;
+
+      if (propertyToDelete.nextProperty != PROPERTY_NULL)
+      {
+        /*
+         * We also need to find a storage for the other link, setup variables
+         * to do this at the end...
+         */
+        needToFindAPlaceholder = TRUE;
+        storeNode              = propertyToDelete.previousProperty;
+        toStoreNode            = propertyToDelete.nextProperty;
+        relationType           = PROPERTY_RELATION_NEXT;
+      }
+    }
+    else if (propertyToDelete.nextProperty != PROPERTY_NULL)
+    {
+      /*
+       * Set the parent next to the property to delete next
+       */
+      newLinkProperty = propertyToDelete.nextProperty;
+    }
+
+    /*
+     * Link it for real...
+     */
+    parentProperty.nextProperty = newLinkProperty;
+  }
+  else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
+  {
+    if (propertyToDelete.previousProperty != PROPERTY_NULL)
+    {
+      /*
+       * Set the parent dir to the property to delete previous
+       */
+      newLinkProperty = propertyToDelete.previousProperty;
+
+      if (propertyToDelete.nextProperty != PROPERTY_NULL)
+      {
+        /*
+         * We also need to find a storage for the other link, setup variables
+         * to do this at the end...
+         */
+        needToFindAPlaceholder = TRUE;
+        storeNode              = propertyToDelete.previousProperty;
+        toStoreNode            = propertyToDelete.nextProperty;
+        relationType           = PROPERTY_RELATION_NEXT;
+      }
+    }
+    else if (propertyToDelete.nextProperty != PROPERTY_NULL)
+    {
+      /*
+       * Set the parent dir to the property to delete next
+       */
+      newLinkProperty = propertyToDelete.nextProperty;
+    }
+
+    /*
+     * Link it for real...
+     */
+    parentProperty.dirProperty = newLinkProperty;
+  }
+
+  /*
+   * Write back the parent property
+   */
+  res = StorageImpl_WriteProperty(
+          This->base.ancestorStorage,
+          parentPropertyId,
+          &parentProperty);
+  if(! res)
+  {
+    return E_FAIL;
+  }
+
+  /*
+   * If a placeholder is required for the other link, then, find one and
+   * get out of here...
+   */
+  if (needToFindAPlaceholder)
+  {
+    hr = findPlaceholder(
+           This,
+           toStoreNode,
+           storeNode,
+           relationType);
+  }
+
+  return hr;
+}
+
+
+/******************************************************************************
+ * SetElementTimes (IStorage)
+ */
+HRESULT WINAPI StorageImpl_SetElementTimes(
+  IStorage*     iface,
+  const OLECHAR *pwcsName,/* [string][in] */
+  const FILETIME  *pctime,  /* [in] */
+  const FILETIME  *patime,  /* [in] */
+  const FILETIME  *pmtime)  /* [in] */
+{
+  FIXME("(%s,...), stub!\n",debugstr_w(pwcsName));
+  return S_OK;
+}
+
+/******************************************************************************
+ * SetStateBits (IStorage)
+ */
+HRESULT WINAPI StorageImpl_SetStateBits(
+  IStorage*   iface,
+  DWORD         grfStateBits,/* [in] */
+  DWORD         grfMask)     /* [in] */
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+/*
+ * Virtual function table for the IStorage32Impl class.
+ */
+static IStorageVtbl Storage32Impl_Vtbl =
+{
+    StorageBaseImpl_QueryInterface,
+    StorageBaseImpl_AddRef,
+    StorageBaseImpl_Release,
+    StorageBaseImpl_CreateStream,
+    StorageBaseImpl_OpenStream,
+    StorageImpl_CreateStorage,
+    StorageBaseImpl_OpenStorage,
+    StorageImpl_CopyTo,
+    StorageImpl_MoveElementTo,
+    StorageImpl_Commit,
+    StorageImpl_Revert,
+    StorageBaseImpl_EnumElements,
+    StorageImpl_DestroyElement,
+    StorageBaseImpl_RenameElement,
+    StorageImpl_SetElementTimes,
+    StorageBaseImpl_SetClass,
+    StorageImpl_SetStateBits,
+    StorageImpl_Stat
+};
+
+HRESULT StorageImpl_Construct(
+  StorageImpl* This,
+  HANDLE       hFile,
+  LPCOLESTR    pwcsName,
+  ILockBytes*  pLkbyt,
+  DWORD        openFlags,
+  BOOL         fileBased,
+  BOOL         fileCreate)
+{
+  HRESULT     hr = S_OK;
+  StgProperty currentProperty;
+  BOOL      readSuccessful;
+  ULONG       currentPropertyIndex;
+
+  if ( FAILED( validateSTGM(openFlags) ))
+    return STG_E_INVALIDFLAG;
+
+  memset(This, 0, sizeof(StorageImpl));
+
+  /*
+   * Initialize the virtual function table.
+   */
+  This->base.lpVtbl = &Storage32Impl_Vtbl;
+  This->base.pssVtbl = &IPropertySetStorage_Vtbl;
+  This->base.v_destructor = &StorageImpl_Destroy;
+  This->base.openFlags = openFlags;
+
+  /*
+   * This is the top-level storage so initialize the ancestor pointer
+   * to this.
+   */
+  This->base.ancestorStorage = This;
+
+  /*
+   * Initialize the physical support of the storage.
+   */
+  This->hFile = hFile;
+
+  /*
+   * Store copy of file path.
+   */
+  if(pwcsName) {
+      This->pwcsName = HeapAlloc(GetProcessHeap(), 0,
+                                (lstrlenW(pwcsName)+1)*sizeof(WCHAR));
+      if (!This->pwcsName)
+         return STG_E_INSUFFICIENTMEMORY;
+      strcpyW(This->pwcsName, pwcsName);
+  }
+
+  /*
+   * Initialize the big block cache.
+   */
+  This->bigBlockSize   = DEF_BIG_BLOCK_SIZE;
+  This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
+  This->bigBlockFile   = BIGBLOCKFILE_Construct(hFile,
+                                                pLkbyt,
+                                                openFlags,
+                                                This->bigBlockSize,
+                                                fileBased);
+
+  if (This->bigBlockFile == 0)
+    return E_FAIL;
+
+  if (fileCreate)
+  {
+    ULARGE_INTEGER size;
+    BYTE* bigBlockBuffer;
+
+    /*
+     * Initialize all header variables:
+     * - The big block depot consists of one block and it is at block 0
+     * - The properties start at block 1
+     * - There is no small block depot
+     */
+    memset( This->bigBlockDepotStart,
+            BLOCK_UNUSED,
+            sizeof(This->bigBlockDepotStart));
+
+    This->bigBlockDepotCount    = 1;
+    This->bigBlockDepotStart[0] = 0;
+    This->rootStartBlock        = 1;
+    This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;
+    This->bigBlockSizeBits      = DEF_BIG_BLOCK_SIZE_BITS;
+    This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;
+    This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
+    This->extBigBlockDepotCount = 0;
+
+    StorageImpl_SaveFileHeader(This);
+
+    /*
+     * Add one block for the big block depot and one block for the properties
+     */
+    size.u.HighPart = 0;
+    size.u.LowPart  = This->bigBlockSize * 3;
+    BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
+
+    /*
+     * Initialize the big block depot
+     */
+    bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
+    memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
+    StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
+    StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
+    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+  }
+  else
+  {
+    /*
+     * Load the header for the file.
+     */
+    hr = StorageImpl_LoadFileHeader(This);
+
+    if (FAILED(hr))
+    {
+      BIGBLOCKFILE_Destructor(This->bigBlockFile);
+
+      return hr;
+    }
+  }
+
+  /*
+   * There is no block depot cached yet.
+   */
+  This->indexBlockDepotCached = 0xFFFFFFFF;
+
+  /*
+   * Start searching for free blocks with block 0.
+   */
+  This->prevFreeBlock = 0;
+
+  /*
+   * Create the block chain abstractions.
+   */
+  if(!(This->rootBlockChain =
+       BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL)))
+    return STG_E_READFAULT;
+
+  if(!(This->smallBlockDepotChain =
+       BlockChainStream_Construct(This, &This->smallBlockDepotStart,
+                                 PROPERTY_NULL)))
+    return STG_E_READFAULT;
+
+  /*
+   * Write the root property
+   */
+  if (fileCreate)
+  {
+    StgProperty rootProp;
+    /*
+     * Initialize the property chain
+     */
+    memset(&rootProp, 0, sizeof(rootProp));
+    MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name,
+                         sizeof(rootProp.name)/sizeof(WCHAR) );
+    rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR);
+    rootProp.propertyType     = PROPTYPE_ROOT;
+    rootProp.previousProperty = PROPERTY_NULL;
+    rootProp.nextProperty     = PROPERTY_NULL;
+    rootProp.dirProperty      = PROPERTY_NULL;
+    rootProp.startingBlock    = BLOCK_END_OF_CHAIN;
+    rootProp.size.u.HighPart    = 0;
+    rootProp.size.u.LowPart     = 0;
+
+    StorageImpl_WriteProperty(This, 0, &rootProp);
+  }
+
+  /*
+   * Find the ID of the root in the property sets.
+   */
+  currentPropertyIndex = 0;
+
+  do
+  {
+    readSuccessful = StorageImpl_ReadProperty(
+                      This,
+                      currentPropertyIndex,
+                      &currentProperty);
+
+    if (readSuccessful)
+    {
+      if ( (currentProperty.sizeOfNameString != 0 ) &&
+           (currentProperty.propertyType     == PROPTYPE_ROOT) )
+      {
+        This->base.rootPropertySetIndex = currentPropertyIndex;
+      }
+    }
+
+    currentPropertyIndex++;
+
+  } while (readSuccessful && (This->base.rootPropertySetIndex == PROPERTY_NULL) );
+
+  if (!readSuccessful)
+  {
+    /* TODO CLEANUP */
+    return STG_E_READFAULT;
+  }
+
+  /*
+   * Create the block chain abstraction for the small block root chain.
+   */
+  if(!(This->smallBlockRootChain =
+       BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex)))
+    return STG_E_READFAULT;
+
+  return hr;
+}
+
+void StorageImpl_Destroy(StorageBaseImpl* iface)
+{
+  StorageImpl *This = (StorageImpl*) iface;
+  TRACE("(%p)\n", This);
+
+  HeapFree(GetProcessHeap(), 0, This->pwcsName);
+
+  BlockChainStream_Destroy(This->smallBlockRootChain);
+  BlockChainStream_Destroy(This->rootBlockChain);
+  BlockChainStream_Destroy(This->smallBlockDepotChain);
+
+  BIGBLOCKFILE_Destructor(This->bigBlockFile);
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ *      Storage32Impl_GetNextFreeBigBlock
+ *
+ * Returns the index of the next free big block.
+ * If the big block depot is filled, this method will enlarge it.
+ *
+ */
+ULONG StorageImpl_GetNextFreeBigBlock(
+  StorageImpl* This)
+{
+  ULONG depotBlockIndexPos;
+  void  *depotBuffer;
+  ULONG depotBlockOffset;
+  ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
+  ULONG nextBlockIndex    = BLOCK_SPECIAL;
+  int   depotIndex        = 0;
+  ULONG freeBlock         = BLOCK_UNUSED;
+
+  depotIndex = This->prevFreeBlock / blocksPerDepot;
+  depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
+
+  /*
+   * Scan the entire big block depot until we find a block marked free
+   */
+  while (nextBlockIndex != BLOCK_UNUSED)
+  {
+    if (depotIndex < COUNT_BBDEPOTINHEADER)
+    {
+      depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
+
+      /*
+       * Grow the primary depot.
+       */
+      if (depotBlockIndexPos == BLOCK_UNUSED)
+      {
+        depotBlockIndexPos = depotIndex*blocksPerDepot;
+
+        /*
+         * Add a block depot.
+         */
+        Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
+        This->bigBlockDepotCount++;
+        This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
+
+        /*
+         * Flag it as a block depot.
+         */
+        StorageImpl_SetNextBlockInChain(This,
+                                          depotBlockIndexPos,
+                                          BLOCK_SPECIAL);
+
+        /* Save new header information.
+         */
+        StorageImpl_SaveFileHeader(This);
+      }
+    }
+    else
+    {
+      depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
+
+      if (depotBlockIndexPos == BLOCK_UNUSED)
+      {
+        /*
+         * Grow the extended depot.
+         */
+        ULONG extIndex       = BLOCK_UNUSED;
+        ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;
+        ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
+
+        if (extBlockOffset == 0)
+        {
+          /* We need an extended block.
+           */
+          extIndex = Storage32Impl_AddExtBlockDepot(This);
+          This->extBigBlockDepotCount++;
+          depotBlockIndexPos = extIndex + 1;
+        }
+        else
+          depotBlockIndexPos = depotIndex * blocksPerDepot;
+
+        /*
+         * Add a block depot and mark it in the extended block.
+         */
+        Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
+        This->bigBlockDepotCount++;
+        Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
+
+        /* Flag the block depot.
+         */
+        StorageImpl_SetNextBlockInChain(This,
+                                          depotBlockIndexPos,
+                                          BLOCK_SPECIAL);
+
+        /* If necessary, flag the extended depot block.
+         */
+        if (extIndex != BLOCK_UNUSED)
+          StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
+
+        /* Save header information.
+         */
+        StorageImpl_SaveFileHeader(This);
+      }
+    }
+
+    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+
+    if (depotBuffer != 0)
+    {
+      while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
+              ( nextBlockIndex != BLOCK_UNUSED))
+      {
+        StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
+
+        if (nextBlockIndex == BLOCK_UNUSED)
+        {
+          freeBlock = (depotIndex * blocksPerDepot) +
+                      (depotBlockOffset/sizeof(ULONG));
+        }
+
+        depotBlockOffset += sizeof(ULONG);
+      }
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+
+    depotIndex++;
+    depotBlockOffset = 0;
+  }
+
+  This->prevFreeBlock = freeBlock;
+
+  return freeBlock;
+}
+
+/******************************************************************************
+ *      Storage32Impl_AddBlockDepot
+ *
+ * This will create a depot block, essentially it is a block initialized
+ * to BLOCK_UNUSEDs.
+ */
+void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
+{
+  BYTE* blockBuffer;
+
+  blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
+
+  /*
+   * Initialize blocks as free
+   */
+  memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
+
+  StorageImpl_ReleaseBigBlock(This, blockBuffer);
+}
+
+/******************************************************************************
+ *      Storage32Impl_GetExtDepotBlock
+ *
+ * Returns the index of the block that corresponds to the specified depot
+ * index. This method is only for depot indexes equal or greater than
+ * COUNT_BBDEPOTINHEADER.
+ */
+ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
+{
+  ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
+  ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
+  ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
+  ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
+  ULONG blockIndex             = BLOCK_UNUSED;
+  ULONG extBlockIndex          = This->extBigBlockDepotStart;
+
+  assert(depotIndex >= COUNT_BBDEPOTINHEADER);
+
+  if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
+    return BLOCK_UNUSED;
+
+  while (extBlockCount > 0)
+  {
+    extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
+    extBlockCount--;
+  }
+
+  if (extBlockIndex != BLOCK_UNUSED)
+  {
+    BYTE* depotBuffer;
+
+    depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
+
+    if (depotBuffer != 0)
+    {
+      StorageUtl_ReadDWord(depotBuffer,
+                           extBlockOffset * sizeof(ULONG),
+                           &blockIndex);
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+  }
+
+  return blockIndex;
+}
+
+/******************************************************************************
+ *      Storage32Impl_SetExtDepotBlock
+ *
+ * Associates the specified block index to the specified depot index.
+ * This method is only for depot indexes equal or greater than
+ * COUNT_BBDEPOTINHEADER.
+ */
+void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
+                                    ULONG depotIndex,
+                                    ULONG blockIndex)
+{
+  ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
+  ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
+  ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
+  ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
+  ULONG extBlockIndex          = This->extBigBlockDepotStart;
+
+  assert(depotIndex >= COUNT_BBDEPOTINHEADER);
+
+  while (extBlockCount > 0)
+  {
+    extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
+    extBlockCount--;
+  }
+
+  if (extBlockIndex != BLOCK_UNUSED)
+  {
+    BYTE* depotBuffer;
+
+    depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
+
+    if (depotBuffer != 0)
+    {
+      StorageUtl_WriteDWord(depotBuffer,
+                            extBlockOffset * sizeof(ULONG),
+                            blockIndex);
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+  }
+}
+
+/******************************************************************************
+ *      Storage32Impl_AddExtBlockDepot
+ *
+ * Creates an extended depot block.
+ */
+ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
+{
+  ULONG numExtBlocks           = This->extBigBlockDepotCount;
+  ULONG nextExtBlock           = This->extBigBlockDepotStart;
+  BYTE* depotBuffer            = NULL;
+  ULONG index                  = BLOCK_UNUSED;
+  ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
+  ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
+  ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
+
+  index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
+          blocksPerDepotBlock;
+
+  if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
+  {
+    /*
+     * The first extended block.
+     */
+    This->extBigBlockDepotStart = index;
+  }
+  else
+  {
+    unsigned int i;
+    /*
+     * Follow the chain to the last one.
+     */
+    for (i = 0; i < (numExtBlocks - 1); i++)
+    {
+      nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
+    }
+
+    /*
+     * Add the new extended block to the chain.
+     */
+    depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
+    StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
+    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  }
+
+  /*
+   * Initialize this block.
+   */
+  depotBuffer = StorageImpl_GetBigBlock(This, index);
+  memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
+  StorageImpl_ReleaseBigBlock(This, depotBuffer);
+
+  return index;
+}
+
+/******************************************************************************
+ *      Storage32Impl_FreeBigBlock
+ *
+ * This method will flag the specified block as free in the big block depot.
+ */
+void  StorageImpl_FreeBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
+
+  if (blockIndex < This->prevFreeBlock)
+    This->prevFreeBlock = blockIndex;
+}
+
+/************************************************************************
+ * Storage32Impl_GetNextBlockInChain
+ *
+ * This method will retrieve the block index of the next big block in
+ * in the chain.
+ *
+ * Params:  This       - Pointer to the Storage object.
+ *          blockIndex - Index of the block to retrieve the chain
+ *                       for.
+ *          nextBlockIndex - receives the return value.
+ *
+ * Returns: This method returns the index of the next block in the chain.
+ *          It will return the constants:
+ *              BLOCK_SPECIAL - If the block given was not part of a
+ *                              chain.
+ *              BLOCK_END_OF_CHAIN - If the block given was the last in
+ *                                   a chain.
+ *              BLOCK_UNUSED - If the block given was not past of a chain
+ *                             and is available.
+ *              BLOCK_EXTBBDEPOT - This block is part of the extended
+ *                                 big block depot.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT StorageImpl_GetNextBlockInChain(
+  StorageImpl* This,
+  ULONG        blockIndex,
+  ULONG*       nextBlockIndex)
+{
+  ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
+  ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
+  ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
+  void* depotBuffer;
+  ULONG depotBlockIndexPos;
+  int index;
+
+  *nextBlockIndex   = BLOCK_SPECIAL;
+
+  if(depotBlockCount >= This->bigBlockDepotCount)
+  {
+    WARN("depotBlockCount %ld, bigBlockDepotCount %ld\n", depotBlockCount,
+        This->bigBlockDepotCount);
+    return STG_E_READFAULT;
+  }
+
+  /*
+   * Cache the currently accessed depot block.
+   */
+  if (depotBlockCount != This->indexBlockDepotCached)
+  {
+    This->indexBlockDepotCached = depotBlockCount;
+
+    if (depotBlockCount < COUNT_BBDEPOTINHEADER)
+    {
+      depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
+    }
+    else
+    {
+      /*
+       * We have to look in the extended depot.
+       */
+      depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
+    }
+
+    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+
+    if (!depotBuffer)
+      return STG_E_READFAULT;
+
+    for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
+    {
+      StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
+      This->blockDepotCached[index] = *nextBlockIndex;
+    }
+    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  }
+
+  *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
+
+  return S_OK;
+}
+
+/******************************************************************************
+ *      Storage32Impl_GetNextExtendedBlock
+ *
+ * Given an extended block this method will return the next extended block.
+ *
+ * NOTES:
+ * The last ULONG of an extended block is the block index of the next
+ * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
+ * depot.
+ *
+ * Return values:
+ *    - The index of the next extended block
+ *    - BLOCK_UNUSED: there is no next extended block.
+ *    - Any other return values denotes failure.
+ */
+ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
+{
+  ULONG nextBlockIndex   = BLOCK_SPECIAL;
+  ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
+  void* depotBuffer;
+
+  depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
+
+  if (depotBuffer!=0)
+  {
+    StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
+
+    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  }
+
+  return nextBlockIndex;
+}
+
+/******************************************************************************
+ *      Storage32Impl_SetNextBlockInChain
+ *
+ * This method will write the index of the specified block's next block
+ * in the big block depot.
+ *
+ * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
+ *              do the following
+ *
+ * Storage32Impl_SetNextBlockInChain(This, 3, 1);
+ * Storage32Impl_SetNextBlockInChain(This, 1, 7);
+ * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
+ *
+ */
+void  StorageImpl_SetNextBlockInChain(
+          StorageImpl* This,
+          ULONG          blockIndex,
+          ULONG          nextBlock)
+{
+  ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
+  ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
+  ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
+  ULONG depotBlockIndexPos;
+  void* depotBuffer;
+
+  assert(depotBlockCount < This->bigBlockDepotCount);
+  assert(blockIndex != nextBlock);
+
+  if (depotBlockCount < COUNT_BBDEPOTINHEADER)
+  {
+    depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
+  }
+  else
+  {
+    /*
+     * We have to look in the extended depot.
+     */
+    depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
+  }
+
+  depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
+
+  if (depotBuffer!=0)
+  {
+    StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
+    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  }
+
+  /*
+   * Update the cached block depot, if necessary.
+   */
+  if (depotBlockCount == This->indexBlockDepotCached)
+  {
+    This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
+  }
+}
+
+/******************************************************************************
+ *      Storage32Impl_LoadFileHeader
+ *
+ * This method will read in the file header, i.e. big block index -1.
+ */
+HRESULT StorageImpl_LoadFileHeader(
+          StorageImpl* This)
+{
+  HRESULT hr = STG_E_FILENOTFOUND;
+  void*   headerBigBlock = NULL;
+  int     index;
+
+  /*
+   * Get a pointer to the big block of data containing the header.
+   */
+  headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
+
+  /*
+   * Extract the information from the header.
+   */
+  if (headerBigBlock!=0)
+  {
+    /*
+     * Check for the "magic number" signature and return an error if it is not
+     * found.
+     */
+    if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
+    {
+      StorageImpl_ReleaseBigBlock(This, headerBigBlock);
+      return STG_E_OLDFORMAT;
+    }
+
+    if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
+    {
+      StorageImpl_ReleaseBigBlock(This, headerBigBlock);
+      return STG_E_INVALIDHEADER;
+    }
+
+    StorageUtl_ReadWord(
+      headerBigBlock,
+      OFFSET_BIGBLOCKSIZEBITS,
+      &This->bigBlockSizeBits);
+
+    StorageUtl_ReadWord(
+      headerBigBlock,
+      OFFSET_SMALLBLOCKSIZEBITS,
+      &This->smallBlockSizeBits);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock,
+      OFFSET_BBDEPOTCOUNT,
+      &This->bigBlockDepotCount);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock,
+      OFFSET_ROOTSTARTBLOCK,
+      &This->rootStartBlock);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock,
+      OFFSET_SBDEPOTSTART,
+      &This->smallBlockDepotStart);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock,
+      OFFSET_EXTBBDEPOTSTART,
+      &This->extBigBlockDepotStart);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock,
+      OFFSET_EXTBBDEPOTCOUNT,
+      &This->extBigBlockDepotCount);
+
+    for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
+    {
+      StorageUtl_ReadDWord(
+        headerBigBlock,
+        OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
+        &(This->bigBlockDepotStart[index]));
+    }
+
+    /*
+     * Make the bitwise arithmetic to get the size of the blocks in bytes.
+     */
+    if ((1 << 2) == 4)
+    {
+      This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
+      This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
+    }
+    else
+    {
+      This->bigBlockSize   = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
+      This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
+    }
+
+    /*
+     * Right now, the code is making some assumptions about the size of the
+     * blocks, just make sure they are what we're expecting.
+     */
+    if (This->bigBlockSize != DEF_BIG_BLOCK_SIZE ||
+       This->smallBlockSize != DEF_SMALL_BLOCK_SIZE)
+    {
+       WARN("Broken OLE storage file\n");
+       hr = STG_E_INVALIDHEADER;
+    }
+    else
+       hr = S_OK;
+
+    /*
+     * Release the block.
+     */
+    StorageImpl_ReleaseBigBlock(This, headerBigBlock);
+  }
+
+  return hr;
+}
+
+/******************************************************************************
+ *      Storage32Impl_SaveFileHeader
+ *
+ * This method will save to the file the header, i.e. big block -1.
+ */
+void StorageImpl_SaveFileHeader(
+          StorageImpl* This)
+{
+  BYTE   headerBigBlock[BIG_BLOCK_SIZE];
+  int    index;
+  BOOL success;
+
+  /*
+   * Get a pointer to the big block of data containing the header.
+   */
+  success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
+
+  /*
+   * If the block read failed, the file is probably new.
+   */
+  if (!success)
+  {
+    /*
+     * Initialize for all unknown fields.
+     */
+    memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
+
+    /*
+     * Initialize the magic number.
+     */
+    memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
+
+    /*
+     * And a bunch of things we don't know what they mean
+     */
+    StorageUtl_WriteWord(headerBigBlock,  0x18, 0x3b);
+    StorageUtl_WriteWord(headerBigBlock,  0x1a, 0x3);
+    StorageUtl_WriteWord(headerBigBlock,  0x1c, (WORD)-2);
+    StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
+  }
+
+  /*
+   * Write the information to the header.
+   */
+  StorageUtl_WriteWord(
+    headerBigBlock,
+    OFFSET_BIGBLOCKSIZEBITS,
+    This->bigBlockSizeBits);
+
+  StorageUtl_WriteWord(
+    headerBigBlock,
+    OFFSET_SMALLBLOCKSIZEBITS,
+    This->smallBlockSizeBits);
+
+  StorageUtl_WriteDWord(
+    headerBigBlock,
+    OFFSET_BBDEPOTCOUNT,
+    This->bigBlockDepotCount);
+
+  StorageUtl_WriteDWord(
+    headerBigBlock,
+    OFFSET_ROOTSTARTBLOCK,
+    This->rootStartBlock);
+
+  StorageUtl_WriteDWord(
+    headerBigBlock,
+    OFFSET_SBDEPOTSTART,
+    This->smallBlockDepotStart);
+
+  StorageUtl_WriteDWord(
+    headerBigBlock,
+    OFFSET_SBDEPOTCOUNT,
+    This->smallBlockDepotChain ?
+     BlockChainStream_GetCount(This->smallBlockDepotChain) : 0);
+
+  StorageUtl_WriteDWord(
+    headerBigBlock,
+    OFFSET_EXTBBDEPOTSTART,
+    This->extBigBlockDepotStart);
+
+  StorageUtl_WriteDWord(
+    headerBigBlock,
+    OFFSET_EXTBBDEPOTCOUNT,
+    This->extBigBlockDepotCount);
+
+  for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
+  {
+    StorageUtl_WriteDWord(
+      headerBigBlock,
+      OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
+      (This->bigBlockDepotStart[index]));
+  }
+
+  /*
+   * Write the big block back to the file.
+   */
+  StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
+}
+
+/******************************************************************************
+ *      Storage32Impl_ReadProperty
+ *
+ * This method will read the specified property from the property chain.
+ */
+BOOL StorageImpl_ReadProperty(
+  StorageImpl* This,
+  ULONG          index,
+  StgProperty*   buffer)
+{
+  BYTE           currentProperty[PROPSET_BLOCK_SIZE];
+  ULARGE_INTEGER offsetInPropSet;
+  BOOL         readSuccessful;
+  ULONG          bytesRead;
+
+  offsetInPropSet.u.HighPart = 0;
+  offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
+
+  readSuccessful = BlockChainStream_ReadAt(
+                    This->rootBlockChain,
+                    offsetInPropSet,
+                    PROPSET_BLOCK_SIZE,
+                    currentProperty,
+                    &bytesRead);
+
+  if (readSuccessful)
+  {
+    /* replace the name of root entry (often "Root Entry") by the file name */
+    WCHAR *propName = (index == This->base.rootPropertySetIndex) ?
+                       This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME;
+
+    memset(buffer->name, 0, sizeof(buffer->name));
+    memcpy(
+      buffer->name,
+      propName,
+      PROPERTY_NAME_BUFFER_LEN );
+    TRACE("storage name: %s\n", debugstr_w(buffer->name));
+
+    memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
+
+    StorageUtl_ReadWord(
+      currentProperty,
+      OFFSET_PS_NAMELENGTH,
+      &buffer->sizeOfNameString);
+
+    StorageUtl_ReadDWord(
+      currentProperty,
+      OFFSET_PS_PREVIOUSPROP,
+      &buffer->previousProperty);
+
+    StorageUtl_ReadDWord(
+      currentProperty,
+      OFFSET_PS_NEXTPROP,
+      &buffer->nextProperty);
+
+    StorageUtl_ReadDWord(
+      currentProperty,
+      OFFSET_PS_DIRPROP,
+      &buffer->dirProperty);
+
+    StorageUtl_ReadGUID(
+      currentProperty,
+      OFFSET_PS_GUID,
+      &buffer->propertyUniqueID);
+
+    StorageUtl_ReadDWord(
+      currentProperty,
+      OFFSET_PS_TSS1,
+      &buffer->timeStampS1);
+
+    StorageUtl_ReadDWord(
+      currentProperty,
+      OFFSET_PS_TSD1,
+      &buffer->timeStampD1);
+
+    StorageUtl_ReadDWord(
+      currentProperty,
+      OFFSET_PS_TSS2,
+      &buffer->timeStampS2);
+
+    StorageUtl_ReadDWord(
+      currentProperty,
+      OFFSET_PS_TSD2,
+      &buffer->timeStampD2);
+
+    StorageUtl_ReadDWord(
+      currentProperty,
+      OFFSET_PS_STARTBLOCK,
+      &buffer->startingBlock);
+
+    StorageUtl_ReadDWord(
+      currentProperty,
+      OFFSET_PS_SIZE,
+      &buffer->size.u.LowPart);
+
+    buffer->size.u.HighPart = 0;
+  }
+
+  return readSuccessful;
+}
+
+/*********************************************************************
+ * Write the specified property into the property chain
+ */
+BOOL StorageImpl_WriteProperty(
+  StorageImpl* This,
+  ULONG          index,
+  StgProperty*   buffer)
+{
+  BYTE           currentProperty[PROPSET_BLOCK_SIZE];
+  ULARGE_INTEGER offsetInPropSet;
+  BOOL         writeSuccessful;
+  ULONG          bytesWritten;
+
+  offsetInPropSet.u.HighPart = 0;
+  offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
+
+  memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
+
+  memcpy(
+    currentProperty + OFFSET_PS_NAME,
+    buffer->name,
+    PROPERTY_NAME_BUFFER_LEN );
+
+  memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
+
+  StorageUtl_WriteWord(
+    currentProperty,
+      OFFSET_PS_NAMELENGTH,
+      buffer->sizeOfNameString);
+
+  StorageUtl_WriteDWord(
+    currentProperty,
+      OFFSET_PS_PREVIOUSPROP,
+      buffer->previousProperty);
+
+  StorageUtl_WriteDWord(
+    currentProperty,
+      OFFSET_PS_NEXTPROP,
+      buffer->nextProperty);
+
+  StorageUtl_WriteDWord(
+    currentProperty,
+      OFFSET_PS_DIRPROP,
+      buffer->dirProperty);
+
+  StorageUtl_WriteGUID(
+    currentProperty,
+      OFFSET_PS_GUID,
+      &buffer->propertyUniqueID);
+
+  StorageUtl_WriteDWord(
+    currentProperty,
+      OFFSET_PS_TSS1,
+      buffer->timeStampS1);
+
+  StorageUtl_WriteDWord(
+    currentProperty,
+      OFFSET_PS_TSD1,
+      buffer->timeStampD1);
+
+  StorageUtl_WriteDWord(
+    currentProperty,
+      OFFSET_PS_TSS2,
+      buffer->timeStampS2);
+
+  StorageUtl_WriteDWord(
+    currentProperty,
+      OFFSET_PS_TSD2,
+      buffer->timeStampD2);
+
+  StorageUtl_WriteDWord(
+    currentProperty,
+      OFFSET_PS_STARTBLOCK,
+      buffer->startingBlock);
+
+  StorageUtl_WriteDWord(
+    currentProperty,
+      OFFSET_PS_SIZE,
+      buffer->size.u.LowPart);
+
+  writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain,
+                                            offsetInPropSet,
+                                            PROPSET_BLOCK_SIZE,
+                                            currentProperty,
+                                            &bytesWritten);
+  return writeSuccessful;
+}
+
+BOOL StorageImpl_ReadBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex,
+  void*          buffer)
+{
+  void* bigBlockBuffer;
+
+  bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
+
+  if (bigBlockBuffer!=0)
+  {
+    memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
+
+    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+BOOL StorageImpl_WriteBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex,
+  void*          buffer)
+{
+  void* bigBlockBuffer;
+
+  bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
+
+  if (bigBlockBuffer!=0)
+  {
+    memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
+
+    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+void* StorageImpl_GetROBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
+}
+
+void* StorageImpl_GetBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
+}
+
+void StorageImpl_ReleaseBigBlock(
+  StorageImpl* This,
+  void*          pBigBlock)
+{
+  BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
+}
+
+/******************************************************************************
+ *              Storage32Impl_SmallBlocksToBigBlocks
+ *
+ * This method will convert a small block chain to a big block chain.
+ * The small block chain will be destroyed.
+ */
+BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
+                      StorageImpl* This,
+                      SmallBlockChainStream** ppsbChain)
+{
+  ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
+  ULARGE_INTEGER size, offset;
+  ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
+  ULONG propertyIndex;
+  BOOL successRead, successWrite;
+  StgProperty chainProperty;
+  BYTE *buffer;
+  BlockChainStream *bbTempChain = NULL;
+  BlockChainStream *bigBlockChain = NULL;
+
+  /*
+   * Create a temporary big block chain that doesn't have
+   * an associated property. This temporary chain will be
+   * used to copy data from small blocks to big blocks.
+   */
+  bbTempChain = BlockChainStream_Construct(This,
+                                           &bbHeadOfChain,
+                                           PROPERTY_NULL);
+  if(!bbTempChain) return NULL;
+  /*
+   * Grow the big block chain.
+   */
+  size = SmallBlockChainStream_GetSize(*ppsbChain);
+  BlockChainStream_SetSize(bbTempChain, size);
+
+  /*
+   * Copy the contents of the small block chain to the big block chain
+   * by small block size increments.
+   */
+  offset.u.LowPart = 0;
+  offset.u.HighPart = 0;
+  cbTotalRead = 0;
+  cbTotalWritten = 0;
+
+  buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
+  do
+  {
+    successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
+                                               offset,
+                                               DEF_SMALL_BLOCK_SIZE,
+                                               buffer,
+                                               &cbRead);
+    cbTotalRead += cbRead;
+
+    successWrite = BlockChainStream_WriteAt(bbTempChain,
+                                            offset,
+                                            cbRead,
+                                            buffer,
+                                            &cbWritten);
+    cbTotalWritten += cbWritten;
+
+    offset.u.LowPart += This->smallBlockSize;
+
+  } while (successRead && successWrite);
+  HeapFree(GetProcessHeap(),0,buffer);
+
+  assert(cbTotalRead == cbTotalWritten);
+
+  /*
+   * Destroy the small block chain.
+   */
+  propertyIndex = (*ppsbChain)->ownerPropertyIndex;
+  size.u.HighPart = 0;
+  size.u.LowPart  = 0;
+  SmallBlockChainStream_SetSize(*ppsbChain, size);
+  SmallBlockChainStream_Destroy(*ppsbChain);
+  *ppsbChain = 0;
+
+  /*
+   * Change the property information. This chain is now a big block chain
+   * and it doesn't reside in the small blocks chain anymore.
+   */
+  StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
+
+  chainProperty.startingBlock = bbHeadOfChain;
+
+  StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
+
+  /*
+   * Destroy the temporary propertyless big block chain.
+   * Create a new big block chain associated with this property.
+   */
+  BlockChainStream_Destroy(bbTempChain);
+  bigBlockChain = BlockChainStream_Construct(This,
+                                             NULL,
+                                             propertyIndex);
+
+  return bigBlockChain;
+}
+
+void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
+{
+  StorageInternalImpl* This = (StorageInternalImpl*) iface;
+
+  StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage);
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+**
+** Storage32InternalImpl_Commit
+**
+** The non-root storages cannot be opened in transacted mode thus this function
+** does nothing.
+*/
+HRESULT WINAPI StorageInternalImpl_Commit(
+  IStorage*            iface,
+  DWORD                  grfCommitFlags)  /* [in] */
+{
+  return S_OK;
+}
+
+/******************************************************************************
+**
+** Storage32InternalImpl_Revert
+**
+** The non-root storages cannot be opened in transacted mode thus this function
+** does nothing.
+*/
+HRESULT WINAPI StorageInternalImpl_Revert(
+  IStorage*            iface)
+{
+  return S_OK;
+}
+
+void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
+{
+  IStorage_Release((IStorage*)This->parentStorage);
+  HeapFree(GetProcessHeap(), 0, This->stackToVisit);
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
+  IEnumSTATSTG*     iface,
+  REFIID            riid,
+  void**            ppvObject)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (ppvObject==0)
+    return E_INVALIDARG;
+
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (IsEqualGUID(&IID_IUnknown, riid) ||
+      IsEqualGUID(&IID_IStorage, riid))
+  {
+    *ppvObject = (IEnumSTATSTG*)This;
+    IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
+    return S_OK;
+  }
+
+  return E_NOINTERFACE;
+}
+
+ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
+  IEnumSTATSTG* iface)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+  return InterlockedIncrement(&This->ref);
+}
+
+ULONG   WINAPI IEnumSTATSTGImpl_Release(
+  IEnumSTATSTG* iface)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  ULONG newRef;
+
+  newRef = InterlockedDecrement(&This->ref);
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (newRef==0)
+  {
+    IEnumSTATSTGImpl_Destroy(This);
+  }
+
+  return newRef;
+}
+
+HRESULT WINAPI IEnumSTATSTGImpl_Next(
+  IEnumSTATSTG* iface,
+  ULONG             celt,
+  STATSTG*          rgelt,
+  ULONG*            pceltFetched)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  StgProperty currentProperty;
+  STATSTG*    currentReturnStruct = rgelt;
+  ULONG       objectFetched       = 0;
+  ULONG      currentSearchNode;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
+    return E_INVALIDARG;
+
+  /*
+   * To avoid the special case, get another pointer to a ULONG value if
+   * the caller didn't supply one.
+   */
+  if (pceltFetched==0)
+    pceltFetched = &objectFetched;
+
+  /*
+   * Start the iteration, we will iterate until we hit the end of the
+   * linked list or until we hit the number of items to iterate through
+   */
+  *pceltFetched = 0;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+
+  while ( ( *pceltFetched < celt) &&
+          ( currentSearchNode!=PROPERTY_NULL) )
+  {
+    /*
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(This->parentStorage,
+      currentSearchNode,
+      &currentProperty);
+
+    /*
+     * Copy the information to the return buffer.
+     */
+    StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
+      &currentProperty,
+      STATFLAG_DEFAULT);
+
+    /*
+     * Step to the next item in the iteration
+     */
+    (*pceltFetched)++;
+    currentReturnStruct++;
+
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  if (*pceltFetched == celt)
+    return S_OK;
+
+  return S_FALSE;
+}
+
+
+HRESULT WINAPI IEnumSTATSTGImpl_Skip(
+  IEnumSTATSTG* iface,
+  ULONG             celt)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  StgProperty currentProperty;
+  ULONG       objectFetched       = 0;
+  ULONG       currentSearchNode;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+
+  while ( (objectFetched < celt) &&
+          (currentSearchNode!=PROPERTY_NULL) )
+  {
+    /*
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(This->parentStorage,
+      currentSearchNode,
+      &currentProperty);
+
+    /*
+     * Step to the next item in the iteration
+     */
+    objectFetched++;
+
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  if (objectFetched == celt)
+    return S_OK;
+
+  return S_FALSE;
+}
+
+HRESULT WINAPI IEnumSTATSTGImpl_Reset(
+  IEnumSTATSTG* iface)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  StgProperty rootProperty;
+  BOOL      readSuccessful;
+
+  /*
+   * Re-initialize the search stack to an empty stack
+   */
+  This->stackSize = 0;
+
+  /*
+   * Read the root property from the storage.
+   */
+  readSuccessful = StorageImpl_ReadProperty(
+                    This->parentStorage,
+                    This->firstPropertyNode,
+                    &rootProperty);
+
+  if (readSuccessful)
+  {
+    assert(rootProperty.sizeOfNameString!=0);
+
+    /*
+     * Push the search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
+  }
+
+  return S_OK;
+}
+
+HRESULT WINAPI IEnumSTATSTGImpl_Clone(
+  IEnumSTATSTG* iface,
+  IEnumSTATSTG**    ppenum)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  IEnumSTATSTGImpl* newClone;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (ppenum==0)
+    return E_INVALIDARG;
+
+  newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
+               This->firstPropertyNode);
+
+
+  /*
+   * The new clone enumeration must point to the same current node as
+   * the ole one.
+   */
+  newClone->stackSize    = This->stackSize    ;
+  newClone->stackMaxSize = This->stackMaxSize ;
+  newClone->stackToVisit =
+    HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
+
+  memcpy(
+    newClone->stackToVisit,
+    This->stackToVisit,
+    sizeof(ULONG) * newClone->stackSize);
+
+  *ppenum = (IEnumSTATSTG*)newClone;
+
+  /*
+   * Don't forget to nail down a reference to the clone before
+   * returning it.
+   */
+  IEnumSTATSTGImpl_AddRef(*ppenum);
+
+  return S_OK;
+}
+
+INT IEnumSTATSTGImpl_FindParentProperty(
+  IEnumSTATSTGImpl *This,
+  ULONG             childProperty,
+  StgProperty      *currentProperty,
+  ULONG            *thisNodeId)
+{
+  ULONG currentSearchNode;
+  ULONG foundNode;
+
+  /*
+   * To avoid the special case, get another pointer to a ULONG value if
+   * the caller didn't supply one.
+   */
+  if (thisNodeId==0)
+    thisNodeId = &foundNode;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+
+
+  while (currentSearchNode!=PROPERTY_NULL)
+  {
+    /*
+     * Store the current node in the returned parameters
+     */
+    *thisNodeId = currentSearchNode;
+
+    /*
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(
+      This->parentStorage,
+      currentSearchNode,
+      currentProperty);
+
+    if (currentProperty->previousProperty == childProperty)
+      return PROPERTY_RELATION_PREVIOUS;
+
+    else if (currentProperty->nextProperty == childProperty)
+      return PROPERTY_RELATION_NEXT;
+
+    else if (currentProperty->dirProperty == childProperty)
+      return PROPERTY_RELATION_DIR;
+
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  return PROPERTY_NULL;
+}
+
+ULONG IEnumSTATSTGImpl_FindProperty(
+  IEnumSTATSTGImpl* This,
+  const OLECHAR*  lpszPropName,
+  StgProperty*      currentProperty)
+{
+  ULONG currentSearchNode;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+
+  while (currentSearchNode!=PROPERTY_NULL)
+  {
+    /*
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(This->parentStorage,
+      currentSearchNode,
+      currentProperty);
+
+    if ( propertyNameCmp(
+          (const OLECHAR*)currentProperty->name,
+          (const OLECHAR*)lpszPropName) == 0)
+      return currentSearchNode;
+
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  return PROPERTY_NULL;
+}
+
+void IEnumSTATSTGImpl_PushSearchNode(
+  IEnumSTATSTGImpl* This,
+  ULONG             nodeToPush)
+{
+  StgProperty rootProperty;
+  BOOL      readSuccessful;
+
+  /*
+   * First, make sure we're not trying to push an unexisting node.
+   */
+  if (nodeToPush==PROPERTY_NULL)
+    return;
+
+  /*
+   * First push the node to the stack
+   */
+  if (This->stackSize == This->stackMaxSize)
+  {
+    This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
+
+    This->stackToVisit = HeapReAlloc(
+                           GetProcessHeap(),
+                           0,
+                           This->stackToVisit,
+                           sizeof(ULONG) * This->stackMaxSize);
+  }
+
+  This->stackToVisit[This->stackSize] = nodeToPush;
+  This->stackSize++;
+
+  /*
+   * Read the root property from the storage.
+   */
+  readSuccessful = StorageImpl_ReadProperty(
+                    This->parentStorage,
+                    nodeToPush,
+                    &rootProperty);
+
+  if (readSuccessful)
+  {
+    assert(rootProperty.sizeOfNameString!=0);
+
+    /*
+     * Push the previous search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
+  }
+}
+
+ULONG IEnumSTATSTGImpl_PopSearchNode(
+  IEnumSTATSTGImpl* This,
+  BOOL            remove)
+{
+  ULONG topNode;
+
+  if (This->stackSize == 0)
+    return PROPERTY_NULL;
+
+  topNode = This->stackToVisit[This->stackSize-1];
+
+  if (remove)
+    This->stackSize--;
+
+  return topNode;
+}
+
+/*
+ * Virtual function table for the IEnumSTATSTGImpl class.
+ */
+static IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
+{
+    IEnumSTATSTGImpl_QueryInterface,
+    IEnumSTATSTGImpl_AddRef,
+    IEnumSTATSTGImpl_Release,
+    IEnumSTATSTGImpl_Next,
+    IEnumSTATSTGImpl_Skip,
+    IEnumSTATSTGImpl_Reset,
+    IEnumSTATSTGImpl_Clone
+};
+
+/******************************************************************************
+** IEnumSTATSTGImpl implementation
+*/
+
+IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
+  StorageImpl* parentStorage,
+  ULONG          firstPropertyNode)
+{
+  IEnumSTATSTGImpl* newEnumeration;
+
+  newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
+
+  if (newEnumeration!=0)
+  {
+    /*
+     * Set-up the virtual function table and reference count.
+     */
+    newEnumeration->lpVtbl    = &IEnumSTATSTGImpl_Vtbl;
+    newEnumeration->ref       = 0;
+
+    /*
+     * We want to nail-down the reference to the storage in case the
+     * enumeration out-lives the storage in the client application.
+     */
+    newEnumeration->parentStorage = parentStorage;
+    IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
+
+    newEnumeration->firstPropertyNode   = firstPropertyNode;
+
+    /*
+     * Initialize the search stack
+     */
+    newEnumeration->stackSize    = 0;
+    newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
+    newEnumeration->stackToVisit =
+      HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
+
+    /*
+     * Make sure the current node of the iterator is the first one.
+     */
+    IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
+  }
+
+  return newEnumeration;
+}
+
+/*
+ * Virtual function table for the Storage32InternalImpl class.
+ */
+static IStorageVtbl Storage32InternalImpl_Vtbl =
+{
+    StorageBaseImpl_QueryInterface,
+    StorageBaseImpl_AddRef,
+    StorageBaseImpl_Release,
+    StorageBaseImpl_CreateStream,
+    StorageBaseImpl_OpenStream,
+    StorageImpl_CreateStorage,
+    StorageBaseImpl_OpenStorage,
+    StorageImpl_CopyTo,
+    StorageImpl_MoveElementTo,
+    StorageInternalImpl_Commit,
+    StorageInternalImpl_Revert,
+    StorageBaseImpl_EnumElements,
+    StorageImpl_DestroyElement,
+    StorageBaseImpl_RenameElement,
+    StorageImpl_SetElementTimes,
+    StorageBaseImpl_SetClass,
+    StorageImpl_SetStateBits,
+    StorageBaseImpl_Stat
+};
+
+/******************************************************************************
+** Storage32InternalImpl implementation
+*/
+
+StorageInternalImpl* StorageInternalImpl_Construct(
+  StorageImpl* ancestorStorage,
+  DWORD        openFlags,
+  ULONG        rootPropertyIndex)
+{
+  StorageInternalImpl* newStorage;
+
+  /*
+   * Allocate space for the new storage object
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
+
+  if (newStorage!=0)
+  {
+    memset(newStorage, 0, sizeof(StorageInternalImpl));
+
+    /*
+     * Initialize the virtual function table.
+     */
+    newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;
+    newStorage->base.v_destructor = &StorageInternalImpl_Destroy;
+    newStorage->base.openFlags = openFlags;
+
+    /*
+     * Keep the ancestor storage pointer and nail a reference to it.
+     */
+    newStorage->base.ancestorStorage = ancestorStorage;
+    StorageBaseImpl_AddRef((IStorage*)(newStorage->base.ancestorStorage));
+
+    /*
+     * Keep the index of the root property set for this storage,
+     */
+    newStorage->base.rootPropertySetIndex = rootPropertyIndex;
+
+    return newStorage;
+  }
+
+  return 0;
+}
+
+/******************************************************************************
+** StorageUtl implementation
+*/
+
+void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value)
+{
+  WORD tmp;
+
+  memcpy(&tmp, buffer+offset, sizeof(WORD));
+  *value = le16toh(tmp);
+}
+
+void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value)
+{
+  value = htole16(value);
+  memcpy(buffer+offset, &value, sizeof(WORD));
+}
+
+void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)
+{
+  DWORD tmp;
+
+  memcpy(&tmp, buffer+offset, sizeof(DWORD));
+  *value = le32toh(tmp);
+}
+
+void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)
+{
+  value = htole32(value);
+  memcpy(buffer+offset, &value, sizeof(DWORD));
+}
+
+void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
+ ULARGE_INTEGER* value)
+{
+#ifdef WORDS_BIGENDIAN
+    ULARGE_INTEGER tmp;
+
+    memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));
+    value->u.LowPart = htole32(tmp.u.HighPart);
+    value->u.HighPart = htole32(tmp.u.LowPart);
+#else
+    memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER));
+#endif
+}
+
+void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
+ const ULARGE_INTEGER *value)
+{
+#ifdef WORDS_BIGENDIAN
+    ULARGE_INTEGER tmp;
+
+    tmp.u.LowPart = htole32(value->u.HighPart);
+    tmp.u.HighPart = htole32(value->u.LowPart);
+    memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER));
+#else
+    memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER));
+#endif
+}
+
+void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value)
+{
+  StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));
+  StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));
+  StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));
+
+  memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
+}
+
+void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value)
+{
+  StorageUtl_WriteDWord(buffer, offset,   value->Data1);
+  StorageUtl_WriteWord(buffer,  offset+4, value->Data2);
+  StorageUtl_WriteWord(buffer,  offset+6, value->Data3);
+
+  memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));
+}
+
+void StorageUtl_CopyPropertyToSTATSTG(
+  STATSTG*     destination,
+  StgProperty* source,
+  int          statFlags)
+{
+  /*
+   * The copy of the string occurs only when the flag is not set
+   */
+  if( ((statFlags & STATFLAG_NONAME) != 0) || 
+       (source->name == NULL) || 
+       (source->name[0] == 0) )
+  {
+    destination->pwcsName = 0;
+  }
+  else
+  {
+    destination->pwcsName =
+      CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
+
+    strcpyW((LPWSTR)destination->pwcsName, source->name);
+  }
+
+  switch (source->propertyType)
+  {
+    case PROPTYPE_STORAGE:
+    case PROPTYPE_ROOT:
+      destination->type = STGTY_STORAGE;
+      break;
+    case PROPTYPE_STREAM:
+      destination->type = STGTY_STREAM;
+      break;
+    default:
+      destination->type = STGTY_STREAM;
+      break;
+  }
+
+  destination->cbSize            = source->size;
+/*
+  currentReturnStruct->mtime     = {0}; TODO
+  currentReturnStruct->ctime     = {0};
+  currentReturnStruct->atime     = {0};
+*/
+  destination->grfMode           = 0;
+  destination->grfLocksSupported = 0;
+  destination->clsid             = source->propertyUniqueID;
+  destination->grfStateBits      = 0;
+  destination->reserved          = 0;
+}
+
+/******************************************************************************
+** BlockChainStream implementation
+*/
+
+BlockChainStream* BlockChainStream_Construct(
+  StorageImpl* parentStorage,
+  ULONG*         headOfStreamPlaceHolder,
+  ULONG          propertyIndex)
+{
+  BlockChainStream* newStream;
+  ULONG blockIndex;
+
+  newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
+
+  newStream->parentStorage           = parentStorage;
+  newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
+  newStream->ownerPropertyIndex      = propertyIndex;
+  newStream->lastBlockNoInSequence   = 0xFFFFFFFF;
+  newStream->tailIndex               = BLOCK_END_OF_CHAIN;
+  newStream->numBlocks               = 0;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(newStream);
+
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    newStream->numBlocks++;
+    newStream->tailIndex = blockIndex;
+
+    if(FAILED(StorageImpl_GetNextBlockInChain(
+             parentStorage,
+             blockIndex,
+             &blockIndex)))
+    {
+      HeapFree(GetProcessHeap(), 0, newStream);
+      return NULL;
+    }
+  }
+
+  return newStream;
+}
+
+void BlockChainStream_Destroy(BlockChainStream* This)
+{
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ *      BlockChainStream_GetHeadOfChain
+ *
+ * Returns the head of this stream chain.
+ * Some special chains don't have properties, their heads are kept in
+ * This->headOfStreamPlaceHolder.
+ *
+ */
+ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
+{
+  StgProperty chainProperty;
+  BOOL      readSuccessful;
+
+  if (This->headOfStreamPlaceHolder != 0)
+    return *(This->headOfStreamPlaceHolder);
+
+  if (This->ownerPropertyIndex != PROPERTY_NULL)
+  {
+    readSuccessful = StorageImpl_ReadProperty(
+                      This->parentStorage,
+                      This->ownerPropertyIndex,
+                      &chainProperty);
+
+    if (readSuccessful)
+    {
+      return chainProperty.startingBlock;
+    }
+  }
+
+  return BLOCK_END_OF_CHAIN;
+}
+
+/******************************************************************************
+ *       BlockChainStream_GetCount
+ *
+ * Returns the number of blocks that comprises this chain.
+ * This is not the size of the stream as the last block may not be full!
+ *
+ */
+ULONG BlockChainStream_GetCount(BlockChainStream* This)
+{
+  ULONG blockIndex;
+  ULONG count = 0;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(This);
+
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    count++;
+
+    if(FAILED(StorageImpl_GetNextBlockInChain(
+                   This->parentStorage,
+                   blockIndex,
+                  &blockIndex)))
+      return 0;
+  }
+
+  return count;
+}
+
+/******************************************************************************
+ *      BlockChainStream_ReadAt
+ *
+ * Reads a specified number of bytes from this chain at the specified offset.
+ * bytesRead may be NULL.
+ * Failure will be returned if the specified number of bytes has not been read.
+ */
+BOOL BlockChainStream_ReadAt(BlockChainStream* This,
+  ULARGE_INTEGER offset,
+  ULONG          size,
+  void*          buffer,
+  ULONG*         bytesRead)
+{
+  ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
+  ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
+  ULONG bytesToReadInBuffer;
+  ULONG blockIndex;
+  BYTE* bufferWalker;
+  BYTE* bigBlockBuffer;
+
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
+       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
+       (blockNoInSequence < This->lastBlockNoInSequence) )
+  {
+    blockIndex = BlockChainStream_GetHeadOfChain(This);
+    This->lastBlockNoInSequence = blockNoInSequence;
+  }
+  else
+  {
+    ULONG temp = blockNoInSequence;
+
+    blockIndex = This->lastBlockNoInSequenceIndex;
+    blockNoInSequence -= This->lastBlockNoInSequence;
+    This->lastBlockNoInSequence = temp;
+  }
+
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
+      return FALSE;
+    blockNoInSequence--;
+  }
+
+  This->lastBlockNoInSequenceIndex = blockIndex;
+
+  /*
+   * Start reading the buffer.
+   */
+  *bytesRead   = 0;
+  bufferWalker = buffer;
+
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy from this big block.
+     */
+    bytesToReadInBuffer =
+      min(This->parentStorage->bigBlockSize - offsetInBlock, size);
+
+    /*
+     * Copy those bytes to the buffer
+     */
+    bigBlockBuffer =
+      StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
+
+    memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
+
+    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+
+    /*
+     * Step to the next big block.
+     */
+    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
+      return FALSE;
+
+    bufferWalker += bytesToReadInBuffer;
+    size         -= bytesToReadInBuffer;
+    *bytesRead   += bytesToReadInBuffer;
+    offsetInBlock = 0;  /* There is no offset on the next block */
+
+  }
+
+  return (size == 0);
+}
+
+/******************************************************************************
+ *      BlockChainStream_WriteAt
+ *
+ * Writes the specified number of bytes to this chain at the specified offset.
+ * bytesWritten may be NULL.
+ * Will fail if not all specified number of bytes have been written.
+ */
+BOOL BlockChainStream_WriteAt(BlockChainStream* This,
+  ULARGE_INTEGER    offset,
+  ULONG             size,
+  const void*       buffer,
+  ULONG*            bytesWritten)
+{
+  ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize;
+  ULONG offsetInBlock     = offset.u.LowPart % This->parentStorage->bigBlockSize;
+  ULONG bytesToWrite;
+  ULONG blockIndex;
+  const BYTE* bufferWalker;
+  BYTE* bigBlockBuffer;
+
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
+       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
+       (blockNoInSequence < This->lastBlockNoInSequence) )
+  {
+    blockIndex = BlockChainStream_GetHeadOfChain(This);
+    This->lastBlockNoInSequence = blockNoInSequence;
+  }
+  else
+  {
+    ULONG temp = blockNoInSequence;
+
+    blockIndex = This->lastBlockNoInSequenceIndex;
+    blockNoInSequence -= This->lastBlockNoInSequence;
+    This->lastBlockNoInSequence = temp;
+  }
+
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
+                                             &blockIndex)))
+      return FALSE;
+    blockNoInSequence--;
+  }
+
+  This->lastBlockNoInSequenceIndex = blockIndex;
+
+  /*
+   * Here, I'm casting away the constness on the buffer variable
+   * This is OK since we don't intend to modify that buffer.
+   */
+  *bytesWritten   = 0;
+  bufferWalker = (const BYTE*)buffer;
+
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy from this big block.
+     */
+    bytesToWrite =
+      min(This->parentStorage->bigBlockSize - offsetInBlock, size);
+
+    /*
+     * Copy those bytes to the buffer
+     */
+    bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
+
+    memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
+
+    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+
+    /*
+     * Step to the next big block.
+     */
+    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
+                                             &blockIndex)))
+      return FALSE;
+    bufferWalker  += bytesToWrite;
+    size          -= bytesToWrite;
+    *bytesWritten += bytesToWrite;
+    offsetInBlock  = 0;      /* There is no offset on the next block */
+  }
+
+  return (size == 0);
+}
+
+/******************************************************************************
+ *      BlockChainStream_Shrink
+ *
+ * Shrinks this chain in the big block depot.
+ */
+BOOL BlockChainStream_Shrink(BlockChainStream* This,
+                               ULARGE_INTEGER    newSize)
+{
+  ULONG blockIndex, extraBlock;
+  ULONG numBlocks;
+  ULONG count = 1;
+
+  /*
+   * Reset the last accessed block cache.
+   */
+  This->lastBlockNoInSequence = 0xFFFFFFFF;
+  This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
+
+  /*
+   * Figure out how many blocks are needed to contain the new size
+   */
+  numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
+
+  if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
+    numBlocks++;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Go to the new end of chain
+   */
+  while (count < numBlocks)
+  {
+    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
+                                             &blockIndex)))
+      return FALSE;
+    count++;
+  }
+
+  /* Get the next block before marking the new end */
+  if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
+                                           &extraBlock)))
+    return FALSE;
+
+  /* Mark the new end of chain */
+  StorageImpl_SetNextBlockInChain(
+    This->parentStorage,
+    blockIndex,
+    BLOCK_END_OF_CHAIN);
+
+  This->tailIndex = blockIndex;
+  This->numBlocks = numBlocks;
+
+  /*
+   * Mark the extra blocks as free
+   */
+  while (extraBlock != BLOCK_END_OF_CHAIN)
+  {
+    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock,
+                                             &blockIndex)))
+      return FALSE;
+    StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
+    extraBlock = blockIndex;
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BlockChainStream_Enlarge
+ *
+ * Grows this chain in the big block depot.
+ */
+BOOL BlockChainStream_Enlarge(BlockChainStream* This,
+                                ULARGE_INTEGER    newSize)
+{
+  ULONG blockIndex, currentBlock;
+  ULONG newNumBlocks;
+  ULONG oldNumBlocks = 0;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Empty chain. Create the head.
+   */
+  if (blockIndex == BLOCK_END_OF_CHAIN)
+  {
+    blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+    StorageImpl_SetNextBlockInChain(This->parentStorage,
+                                      blockIndex,
+                                      BLOCK_END_OF_CHAIN);
+
+    if (This->headOfStreamPlaceHolder != 0)
+    {
+      *(This->headOfStreamPlaceHolder) = blockIndex;
+    }
+    else
+    {
+      StgProperty chainProp;
+      assert(This->ownerPropertyIndex != PROPERTY_NULL);
+
+      StorageImpl_ReadProperty(
+        This->parentStorage,
+        This->ownerPropertyIndex,
+        &chainProp);
+
+      chainProp.startingBlock = blockIndex;
+
+      StorageImpl_WriteProperty(
+        This->parentStorage,
+        This->ownerPropertyIndex,
+        &chainProp);
+    }
+
+    This->tailIndex = blockIndex;
+    This->numBlocks = 1;
+  }
+
+  /*
+   * Figure out how many blocks are needed to contain this stream
+   */
+  newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize;
+
+  if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
+    newNumBlocks++;
+
+  /*
+   * Go to the current end of chain
+   */
+  if (This->tailIndex == BLOCK_END_OF_CHAIN)
+  {
+    currentBlock = blockIndex;
+
+    while (blockIndex != BLOCK_END_OF_CHAIN)
+    {
+      This->numBlocks++;
+      currentBlock = blockIndex;
+
+      if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock,
+                                               &blockIndex)))
+       return FALSE;
+    }
+
+    This->tailIndex = currentBlock;
+  }
+
+  currentBlock = This->tailIndex;
+  oldNumBlocks = This->numBlocks;
+
+  /*
+   * Add new blocks to the chain
+   */
+  if (oldNumBlocks < newNumBlocks)
+  {
+    while (oldNumBlocks < newNumBlocks)
+    {
+      blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+
+      StorageImpl_SetNextBlockInChain(
+       This->parentStorage,
+       currentBlock,
+       blockIndex);
+
+      StorageImpl_SetNextBlockInChain(
+        This->parentStorage,
+       blockIndex,
+       BLOCK_END_OF_CHAIN);
+
+      currentBlock = blockIndex;
+      oldNumBlocks++;
+    }
+
+    This->tailIndex = blockIndex;
+    This->numBlocks = newNumBlocks;
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BlockChainStream_SetSize
+ *
+ * Sets the size of this stream. The big block depot will be updated.
+ * The file will grow if we grow the chain.
+ *
+ * TODO: Free the actual blocks in the file when we shrink the chain.
+ *       Currently, the blocks are still in the file. So the file size
+ *       doesn't shrink even if we shrink streams.
+ */
+BOOL BlockChainStream_SetSize(
+  BlockChainStream* This,
+  ULARGE_INTEGER    newSize)
+{
+  ULARGE_INTEGER size = BlockChainStream_GetSize(This);
+
+  if (newSize.u.LowPart == size.u.LowPart)
+    return TRUE;
+
+  if (newSize.u.LowPart < size.u.LowPart)
+  {
+    BlockChainStream_Shrink(This, newSize);
+  }
+  else
+  {
+    ULARGE_INTEGER fileSize =
+      BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
+
+    ULONG diff = newSize.u.LowPart - size.u.LowPart;
+
+    /*
+     * Make sure the file stays a multiple of blocksize
+     */
+    if ((diff % This->parentStorage->bigBlockSize) != 0)
+      diff += (This->parentStorage->bigBlockSize -
+                (diff % This->parentStorage->bigBlockSize) );
+
+    fileSize.u.LowPart += diff;
+    BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
+
+    BlockChainStream_Enlarge(This, newSize);
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BlockChainStream_GetSize
+ *
+ * Returns the size of this chain.
+ * Will return the block count if this chain doesn't have a property.
+ */
+ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
+{
+  StgProperty chainProperty;
+
+  if(This->headOfStreamPlaceHolder == NULL)
+  {
+    /*
+     * This chain is a data stream read the property and return
+     * the appropriate size
+     */
+    StorageImpl_ReadProperty(
+      This->parentStorage,
+      This->ownerPropertyIndex,
+      &chainProperty);
+
+    return chainProperty.size;
+  }
+  else
+  {
+    /*
+     * this chain is a chain that does not have a property, figure out the
+     * size by making the product number of used blocks times the
+     * size of them
+     */
+    ULARGE_INTEGER result;
+    result.u.HighPart = 0;
+
+    result.u.LowPart  =
+      BlockChainStream_GetCount(This) *
+      This->parentStorage->bigBlockSize;
+
+    return result;
+  }
+}
+
+/******************************************************************************
+** SmallBlockChainStream implementation
+*/
+
+SmallBlockChainStream* SmallBlockChainStream_Construct(
+  StorageImpl* parentStorage,
+  ULONG          propertyIndex)
+{
+  SmallBlockChainStream* newStream;
+
+  newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
+
+  newStream->parentStorage      = parentStorage;
+  newStream->ownerPropertyIndex = propertyIndex;
+
+  return newStream;
+}
+
+void SmallBlockChainStream_Destroy(
+  SmallBlockChainStream* This)
+{
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetHeadOfChain
+ *
+ * Returns the head of this chain of small blocks.
+ */
+ULONG SmallBlockChainStream_GetHeadOfChain(
+  SmallBlockChainStream* This)
+{
+  StgProperty chainProperty;
+  BOOL      readSuccessful;
+
+  if (This->ownerPropertyIndex)
+  {
+    readSuccessful = StorageImpl_ReadProperty(
+                      This->parentStorage,
+                      This->ownerPropertyIndex,
+                      &chainProperty);
+
+    if (readSuccessful)
+    {
+      return chainProperty.startingBlock;
+    }
+
+  }
+
+  return BLOCK_END_OF_CHAIN;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetNextBlockInChain
+ *
+ * Returns the index of the next small block in this chain.
+ *
+ * Return Values:
+ *    - BLOCK_END_OF_CHAIN: end of this chain
+ *    - BLOCK_UNUSED: small block 'blockIndex' is free
+ */
+HRESULT SmallBlockChainStream_GetNextBlockInChain(
+  SmallBlockChainStream* This,
+  ULONG                  blockIndex,
+  ULONG*                 nextBlockInChain)
+{
+  ULARGE_INTEGER offsetOfBlockInDepot;
+  DWORD  buffer;
+  ULONG  bytesRead;
+  BOOL success;
+
+  *nextBlockInChain = BLOCK_END_OF_CHAIN;
+
+  offsetOfBlockInDepot.u.HighPart = 0;
+  offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
+
+  /*
+   * Read those bytes in the buffer from the small block file.
+   */
+  success = BlockChainStream_ReadAt(
+              This->parentStorage->smallBlockDepotChain,
+              offsetOfBlockInDepot,
+              sizeof(DWORD),
+              &buffer,
+              &bytesRead);
+
+  if (success)
+  {
+    StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
+    return S_OK;
+  }
+
+  return STG_E_READFAULT;
+}
+
+/******************************************************************************
+ *       SmallBlockChainStream_SetNextBlockInChain
+ *
+ * Writes the index of the next block of the specified block in the small
+ * block depot.
+ * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
+ * To flag a block as free use BLOCK_UNUSED as nextBlock.
+ */
+void SmallBlockChainStream_SetNextBlockInChain(
+  SmallBlockChainStream* This,
+  ULONG                  blockIndex,
+  ULONG                  nextBlock)
+{
+  ULARGE_INTEGER offsetOfBlockInDepot;
+  DWORD  buffer;
+  ULONG  bytesWritten;
+
+  offsetOfBlockInDepot.u.HighPart = 0;
+  offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
+
+  StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
+
+  /*
+   * Read those bytes in the buffer from the small block file.
+   */
+  BlockChainStream_WriteAt(
+    This->parentStorage->smallBlockDepotChain,
+    offsetOfBlockInDepot,
+    sizeof(DWORD),
+    &buffer,
+    &bytesWritten);
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_FreeBlock
+ *
+ * Flag small block 'blockIndex' as free in the small block depot.
+ */
+void SmallBlockChainStream_FreeBlock(
+  SmallBlockChainStream* This,
+  ULONG                  blockIndex)
+{
+  SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetNextFreeBlock
+ *
+ * Returns the index of a free small block. The small block depot will be
+ * enlarged if necessary. The small block chain will also be enlarged if
+ * necessary.
+ */
+ULONG SmallBlockChainStream_GetNextFreeBlock(
+  SmallBlockChainStream* This)
+{
+  ULARGE_INTEGER offsetOfBlockInDepot;
+  DWORD buffer;
+  ULONG bytesRead;
+  ULONG blockIndex = 0;
+  ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
+  BOOL success = TRUE;
+  ULONG smallBlocksPerBigBlock;
+
+  offsetOfBlockInDepot.u.HighPart = 0;
+
+  /*
+   * Scan the small block depot for a free block
+   */
+  while (nextBlockIndex != BLOCK_UNUSED)
+  {
+    offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
+
+    success = BlockChainStream_ReadAt(
+                This->parentStorage->smallBlockDepotChain,
+                offsetOfBlockInDepot,
+                sizeof(DWORD),
+                &buffer,
+                &bytesRead);
+
+    /*
+     * If we run out of space for the small block depot, enlarge it
+     */
+    if (success)
+    {
+      StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
+
+      if (nextBlockIndex != BLOCK_UNUSED)
+        blockIndex++;
+    }
+    else
+    {
+      ULONG count =
+        BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
+
+      ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
+      ULONG nextBlock, newsbdIndex;
+      BYTE* smallBlockDepot;
+
+      nextBlock = sbdIndex;
+      while (nextBlock != BLOCK_END_OF_CHAIN)
+      {
+        sbdIndex = nextBlock;
+       StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock);
+      }
+
+      newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+      if (sbdIndex != BLOCK_END_OF_CHAIN)
+        StorageImpl_SetNextBlockInChain(
+          This->parentStorage,
+          sbdIndex,
+          newsbdIndex);
+
+      StorageImpl_SetNextBlockInChain(
+        This->parentStorage,
+        newsbdIndex,
+        BLOCK_END_OF_CHAIN);
+
+      /*
+       * Initialize all the small blocks to free
+       */
+      smallBlockDepot =
+        StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
+
+      memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
+      StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
+
+      if (count == 0)
+      {
+        /*
+         * We have just created the small block depot.
+         */
+        StgProperty rootProp;
+        ULONG sbStartIndex;
+
+        /*
+         * Save it in the header
+         */
+        This->parentStorage->smallBlockDepotStart = newsbdIndex;
+        StorageImpl_SaveFileHeader(This->parentStorage);
+
+        /*
+         * And allocate the first big block that will contain small blocks
+         */
+        sbStartIndex =
+          StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+
+        StorageImpl_SetNextBlockInChain(
+          This->parentStorage,
+          sbStartIndex,
+          BLOCK_END_OF_CHAIN);
+
+        StorageImpl_ReadProperty(
+          This->parentStorage,
+          This->parentStorage->base.rootPropertySetIndex,
+          &rootProp);
+
+        rootProp.startingBlock = sbStartIndex;
+        rootProp.size.u.HighPart = 0;
+        rootProp.size.u.LowPart  = This->parentStorage->bigBlockSize;
+
+        StorageImpl_WriteProperty(
+          This->parentStorage,
+          This->parentStorage->base.rootPropertySetIndex,
+          &rootProp);
+      }
+    }
+  }
+
+  smallBlocksPerBigBlock =
+    This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
+
+  /*
+   * Verify if we have to allocate big blocks to contain small blocks
+   */
+  if (blockIndex % smallBlocksPerBigBlock == 0)
+  {
+    StgProperty rootProp;
+    ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
+
+    StorageImpl_ReadProperty(
+      This->parentStorage,
+      This->parentStorage->base.rootPropertySetIndex,
+      &rootProp);
+
+    if (rootProp.size.u.LowPart <
+       (blocksRequired * This->parentStorage->bigBlockSize))
+    {
+      rootProp.size.u.LowPart += This->parentStorage->bigBlockSize;
+
+      BlockChainStream_SetSize(
+        This->parentStorage->smallBlockRootChain,
+        rootProp.size);
+
+      StorageImpl_WriteProperty(
+        This->parentStorage,
+        This->parentStorage->base.rootPropertySetIndex,
+        &rootProp);
+    }
+  }
+
+  return blockIndex;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_ReadAt
+ *
+ * Reads a specified number of bytes from this chain at the specified offset.
+ * bytesRead may be NULL.
+ * Failure will be returned if the specified number of bytes has not been read.
+ */
+BOOL SmallBlockChainStream_ReadAt(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER         offset,
+  ULONG                  size,
+  void*                  buffer,
+  ULONG*                 bytesRead)
+{
+  ULARGE_INTEGER offsetInBigBlockFile;
+  ULONG blockNoInSequence =
+    offset.u.LowPart / This->parentStorage->smallBlockSize;
+
+  ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
+  ULONG bytesToReadInBuffer;
+  ULONG blockIndex;
+  ULONG bytesReadFromBigBlockFile;
+  BYTE* bufferWalker;
+
+  /*
+   * This should never happen on a small block file.
+   */
+  assert(offset.u.HighPart==0);
+
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
+                                                       &blockIndex)))
+      return FALSE;
+    blockNoInSequence--;
+  }
+
+  /*
+   * Start reading the buffer.
+   */
+  *bytesRead   = 0;
+  bufferWalker = buffer;
+
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy from this small block.
+     */
+    bytesToReadInBuffer =
+      min(This->parentStorage->smallBlockSize - offsetInBlock, size);
+
+    /*
+     * Calculate the offset of the small block in the small block file.
+     */
+    offsetInBigBlockFile.u.HighPart  = 0;
+    offsetInBigBlockFile.u.LowPart   =
+      blockIndex * This->parentStorage->smallBlockSize;
+
+    offsetInBigBlockFile.u.LowPart  += offsetInBlock;
+
+    /*
+     * Read those bytes in the buffer from the small block file.
+     */
+    BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
+      offsetInBigBlockFile,
+      bytesToReadInBuffer,
+      bufferWalker,
+      &bytesReadFromBigBlockFile);
+
+    assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
+
+    /*
+     * Step to the next big block.
+     */
+    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
+      return FALSE;
+    bufferWalker += bytesToReadInBuffer;
+    size         -= bytesToReadInBuffer;
+    *bytesRead   += bytesToReadInBuffer;
+    offsetInBlock = 0;  /* There is no offset on the next block */
+  }
+
+  return (size == 0);
+}
+
+/******************************************************************************
+ *       SmallBlockChainStream_WriteAt
+ *
+ * Writes the specified number of bytes to this chain at the specified offset.
+ * bytesWritten may be NULL.
+ * Will fail if not all specified number of bytes have been written.
+ */
+BOOL SmallBlockChainStream_WriteAt(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER offset,
+  ULONG          size,
+  const void*    buffer,
+  ULONG*         bytesWritten)
+{
+  ULARGE_INTEGER offsetInBigBlockFile;
+  ULONG blockNoInSequence =
+    offset.u.LowPart / This->parentStorage->smallBlockSize;
+
+  ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
+  ULONG bytesToWriteInBuffer;
+  ULONG blockIndex;
+  ULONG bytesWrittenFromBigBlockFile;
+  const BYTE* bufferWalker;
+
+  /*
+   * This should never happen on a small block file.
+   */
+  assert(offset.u.HighPart==0);
+
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
+      return FALSE;
+    blockNoInSequence--;
+  }
+
+  /*
+   * Start writing the buffer.
+   *
+   * Here, I'm casting away the constness on the buffer variable
+   * This is OK since we don't intend to modify that buffer.
+   */
+  *bytesWritten   = 0;
+  bufferWalker = (const BYTE*)buffer;
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy to this small block.
+     */
+    bytesToWriteInBuffer =
+      min(This->parentStorage->smallBlockSize - offsetInBlock, size);
+
+    /*
+     * Calculate the offset of the small block in the small block file.
+     */
+    offsetInBigBlockFile.u.HighPart  = 0;
+    offsetInBigBlockFile.u.LowPart   =
+      blockIndex * This->parentStorage->smallBlockSize;
+
+    offsetInBigBlockFile.u.LowPart  += offsetInBlock;
+
+    /*
+     * Write those bytes in the buffer to the small block file.
+     */
+    BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
+      offsetInBigBlockFile,
+      bytesToWriteInBuffer,
+      bufferWalker,
+      &bytesWrittenFromBigBlockFile);
+
+    assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
+
+    /*
+     * Step to the next big block.
+     */
+    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
+                                                       &blockIndex)))
+      return FALSE;
+    bufferWalker  += bytesToWriteInBuffer;
+    size          -= bytesToWriteInBuffer;
+    *bytesWritten += bytesToWriteInBuffer;
+    offsetInBlock  = 0;     /* There is no offset on the next block */
+  }
+
+  return (size == 0);
+}
+
+/******************************************************************************
+ *       SmallBlockChainStream_Shrink
+ *
+ * Shrinks this chain in the small block depot.
+ */
+BOOL SmallBlockChainStream_Shrink(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER newSize)
+{
+  ULONG blockIndex, extraBlock;
+  ULONG numBlocks;
+  ULONG count = 0;
+
+  numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
+
+  if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
+    numBlocks++;
+
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Go to the new end of chain
+   */
+  while (count < numBlocks)
+  {
+    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
+                                                       &blockIndex)))
+      return FALSE;
+    count++;
+  }
+
+  /*
+   * If the count is 0, we have a special case, the head of the chain was
+   * just freed.
+   */
+  if (count == 0)
+  {
+    StgProperty chainProp;
+
+    StorageImpl_ReadProperty(This->parentStorage,
+                            This->ownerPropertyIndex,
+                            &chainProp);
+
+    chainProp.startingBlock = BLOCK_END_OF_CHAIN;
+
+    StorageImpl_WriteProperty(This->parentStorage,
+                             This->ownerPropertyIndex,
+                             &chainProp);
+
+    /*
+     * We start freeing the chain at the head block.
+     */
+    extraBlock = blockIndex;
+  }
+  else
+  {
+    /* Get the next block before marking the new end */
+    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
+                                                       &extraBlock)))
+      return FALSE;
+
+    /* Mark the new end of chain */
+    SmallBlockChainStream_SetNextBlockInChain(
+      This,
+      blockIndex,
+      BLOCK_END_OF_CHAIN);
+  }
+
+  /*
+   * Mark the extra blocks as free
+   */
+  while (extraBlock != BLOCK_END_OF_CHAIN)
+  {
+    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock,
+                                                       &blockIndex)))
+      return FALSE;
+    SmallBlockChainStream_FreeBlock(This, extraBlock);
+    extraBlock = blockIndex;
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_Enlarge
+ *
+ * Grows this chain in the small block depot.
+ */
+BOOL SmallBlockChainStream_Enlarge(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER newSize)
+{
+  ULONG blockIndex, currentBlock;
+  ULONG newNumBlocks;
+  ULONG oldNumBlocks = 0;
+
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Empty chain
+   */
+  if (blockIndex == BLOCK_END_OF_CHAIN)
+  {
+
+    StgProperty chainProp;
+
+    StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
+                               &chainProp);
+
+    chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
+
+    StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
+                                &chainProp);
+
+    blockIndex = chainProp.startingBlock;
+    SmallBlockChainStream_SetNextBlockInChain(
+      This,
+      blockIndex,
+      BLOCK_END_OF_CHAIN);
+  }
+
+  currentBlock = blockIndex;
+
+  /*
+   * Figure out how many blocks are needed to contain this stream
+   */
+  newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize;
+
+  if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0)
+    newNumBlocks++;
+
+  /*
+   * Go to the current end of chain
+   */
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    oldNumBlocks++;
+    currentBlock = blockIndex;
+    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
+      return FALSE;
+  }
+
+  /*
+   * Add new blocks to the chain
+   */
+  while (oldNumBlocks < newNumBlocks)
+  {
+    blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
+    SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
+
+    SmallBlockChainStream_SetNextBlockInChain(
+      This,
+      blockIndex,
+      BLOCK_END_OF_CHAIN);
+
+    currentBlock = blockIndex;
+    oldNumBlocks++;
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetCount
+ *
+ * Returns the number of blocks that comprises this chain.
+ * This is not the size of this chain as the last block may not be full!
+ */
+ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
+{
+  ULONG blockIndex;
+  ULONG count = 0;
+
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    count++;
+
+    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
+      return 0;
+  }
+
+  return count;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_SetSize
+ *
+ * Sets the size of this stream.
+ * The file will grow if we grow the chain.
+ *
+ * TODO: Free the actual blocks in the file when we shrink the chain.
+ *       Currently, the blocks are still in the file. So the file size
+ *       doesn't shrink even if we shrink streams.
+ */
+BOOL SmallBlockChainStream_SetSize(
+                SmallBlockChainStream* This,
+                ULARGE_INTEGER    newSize)
+{
+  ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
+
+  if (newSize.u.LowPart == size.u.LowPart)
+    return TRUE;
+
+  if (newSize.u.LowPart < size.u.LowPart)
+  {
+    SmallBlockChainStream_Shrink(This, newSize);
+  }
+  else
+  {
+    SmallBlockChainStream_Enlarge(This, newSize);
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetSize
+ *
+ * Returns the size of this chain.
+ */
+ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
+{
+  StgProperty chainProperty;
+
+  StorageImpl_ReadProperty(
+    This->parentStorage,
+    This->ownerPropertyIndex,
+    &chainProperty);
+
+  return chainProperty.size;
+}
+
+/******************************************************************************
+ *    StgCreateDocfile  [OLE32.@]
+ */
+HRESULT WINAPI StgCreateDocfile(
+  LPCOLESTR pwcsName,
+  DWORD       grfMode,
+  DWORD       reserved,
+  IStorage  **ppstgOpen)
+{
+  StorageImpl* newStorage = 0;
+  HANDLE       hFile      = INVALID_HANDLE_VALUE;
+  HRESULT        hr         = STG_E_INVALIDFLAG;
+  DWORD          shareMode;
+  DWORD          accessMode;
+  DWORD          creationMode;
+  DWORD          fileAttributes;
+  WCHAR          tempFileName[MAX_PATH];
+
+  TRACE("(%s, %lx, %ld, %p)\n",
+       debugstr_w(pwcsName), grfMode,
+       reserved, ppstgOpen);
+
+  /*
+   * Validate the parameters
+   */
+  if (ppstgOpen == 0)
+    return STG_E_INVALIDPOINTER;
+  if (reserved != 0)
+    return STG_E_INVALIDPARAMETER;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    goto end;
+
+  /* StgCreateDocFile always opens for write */
+  switch(STGM_ACCESS_MODE(grfMode))
+  {
+  case STGM_WRITE:
+  case STGM_READWRITE:
+    break;
+  default:
+    goto end;
+  }
+
+  /* can't share write */
+  switch(STGM_SHARE_MODE(grfMode))
+  {
+  case STGM_SHARE_EXCLUSIVE:
+  case STGM_SHARE_DENY_WRITE:
+    break;
+  default:
+    goto end;
+  }
+
+  /* shared reading requires transacted mode */
+  if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
+     !(grfMode&STGM_TRANSACTED) )
+    goto end;
+
+  /*
+   * Generate a unique name.
+   */
+  if (pwcsName == 0)
+  {
+    WCHAR tempPath[MAX_PATH];
+    static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
+
+    if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
+      goto end;
+
+    memset(tempPath, 0, sizeof(tempPath));
+    memset(tempFileName, 0, sizeof(tempFileName));
+
+    if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
+      tempPath[0] = '.';
+
+    if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
+      pwcsName = tempFileName;
+    else
+    {
+      hr = STG_E_INSUFFICIENTMEMORY;
+      goto end;
+    }
+
+    creationMode = TRUNCATE_EXISTING;
+  }
+  else
+  {
+    creationMode = GetCreationModeFromSTGM(grfMode);
+  }
+
+  /*
+   * Interpret the STGM value grfMode
+   */
+  shareMode    = GetShareModeFromSTGM(grfMode);
+  accessMode   = GetAccessModeFromSTGM(grfMode);
+
+  if (grfMode & STGM_DELETEONRELEASE)
+    fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
+  else
+    fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
+
+  if (grfMode & STGM_TRANSACTED)
+    FIXME("Transacted mode not implemented.\n");
+
+  /*
+   * Initialize the "out" parameter.
+   */
+  *ppstgOpen = 0;
+
+  hFile = CreateFileW(pwcsName,
+                        accessMode,
+                        shareMode,
+                        NULL,
+                        creationMode,
+                        fileAttributes,
+                        0);
+
+  if (hFile == INVALID_HANDLE_VALUE)
+  {
+    if(GetLastError() == ERROR_FILE_EXISTS)
+      hr = STG_E_FILEALREADYEXISTS;
+    else
+      hr = E_FAIL;
+    goto end;
+  }
+
+  /*
+   * Allocate and initialize the new IStorage32object.
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+
+  if (newStorage == 0)
+  {
+    hr = STG_E_INSUFFICIENTMEMORY;
+    goto end;
+  }
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         hFile,
+        pwcsName,
+         NULL,
+         grfMode,
+         TRUE,
+         TRUE);
+
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    goto end;
+  }
+
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+end:
+  TRACE("<-- %p  r = %08lx\n", *ppstgOpen, hr);
+
+  return hr;
+}
+
+/******************************************************************************
+ *              StgCreateStorageEx        [OLE32.@]
+ */
+HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
+{
+    TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
+          grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
+
+    if (stgfmt != STGFMT_FILE && grfAttrs != 0)
+    {
+        ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
+        return STG_E_INVALIDPARAMETER;  
+    }
+
+    if (stgfmt != STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
+    {
+        ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
+        return STG_E_INVALIDPARAMETER;  
+    }
+
+    if (stgfmt == STGFMT_FILE)
+    {
+        ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
+        return STG_E_INVALIDPARAMETER;
+    }
+
+    if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
+    {
+        FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n");
+        return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); 
+    }
+
+    ERR("Invalid stgfmt argument\n");
+    return STG_E_INVALIDPARAMETER;
+}
+
+/******************************************************************************
+ *              StgCreatePropSetStg       [OLE32.@]
+ */
+HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
+ IPropertySetStorage **ppPropSetStg)
+{
+    HRESULT hr;
+
+    TRACE("(%p, 0x%lx, %p): stub\n", pstg, reserved, ppPropSetStg);
+    if (reserved)
+        hr = STG_E_INVALIDPARAMETER;
+    else
+        hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
+         (void**)ppPropSetStg);
+    return hr;
+}
+
+/******************************************************************************
+ *              StgOpenStorageEx      [OLE32.@]
+ */
+HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
+{
+    TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
+          grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
+
+    if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
+    {
+        ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
+        return STG_E_INVALIDPARAMETER;  
+    }
+
+    if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
+    {
+        ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
+        return STG_E_INVALIDPARAMETER;  
+    }
+
+    if (stgfmt == STGFMT_FILE)
+    {
+        ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
+        return STG_E_INVALIDPARAMETER;
+    }
+
+    if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE || stgfmt == STGFMT_ANY)
+    {
+        if (stgfmt == STGFMT_ANY) 
+            WARN("STGFMT_ANY assuming storage\n");
+        FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
+        return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); 
+    }
+
+    ERR("Invalid stgfmt argument\n");
+    return STG_E_INVALIDPARAMETER;
+}
+
+
+/******************************************************************************
+ *              StgOpenStorage        [OLE32.@]
+ */
+HRESULT WINAPI StgOpenStorage(
+  const OLECHAR *pwcsName,
+  IStorage      *pstgPriority,
+  DWORD           grfMode,
+  SNB           snbExclude,
+  DWORD           reserved,
+  IStorage      **ppstgOpen)
+{
+  StorageImpl* newStorage = 0;
+  HRESULT        hr = S_OK;
+  HANDLE       hFile = 0;
+  DWORD          shareMode;
+  DWORD          accessMode;
+  WCHAR          fullname[MAX_PATH];
+  DWORD          length;
+
+  TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
+       debugstr_w(pwcsName), pstgPriority, grfMode,
+       snbExclude, reserved, ppstgOpen);
+
+  /*
+   * Perform sanity checks
+   */
+  if (pwcsName == 0)
+  {
+    hr = STG_E_INVALIDNAME;
+    goto end;
+  }
+
+  if (ppstgOpen == 0)
+  {
+    hr = STG_E_INVALIDPOINTER;
+    goto end;
+  }
+
+  if (reserved)
+  {
+    hr = STG_E_INVALIDPARAMETER;
+    goto end;
+  }
+
+  /*
+   * Validate the sharing mode
+   */
+  switch(STGM_SHARE_MODE(grfMode))
+  {
+  case STGM_SHARE_EXCLUSIVE:
+  case STGM_SHARE_DENY_WRITE:
+    break;
+  default:
+    hr = STG_E_INVALIDFLAG;
+    goto end;
+  }
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ) ||
+       (grfMode&STGM_CREATE))
+  {
+    hr = STG_E_INVALIDFLAG;
+    goto end;
+  }
+
+  /* shared reading requires transacted mode */
+  if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
+      STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
+     !(grfMode&STGM_TRANSACTED) )
+  {
+    hr = STG_E_INVALIDFLAG;
+    goto end;
+  }
+
+  /*
+   * Interpret the STGM value grfMode
+   */
+  shareMode    = GetShareModeFromSTGM(grfMode);
+  accessMode   = GetAccessModeFromSTGM(grfMode);
+
+  /*
+   * Initialize the "out" parameter.
+   */
+  *ppstgOpen = 0;
+
+  hFile = CreateFileW( pwcsName,
+                       accessMode,
+                       shareMode,
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+                       0);
+
+  if (hFile==INVALID_HANDLE_VALUE)
+  {
+    DWORD last_error = GetLastError();
+
+    hr = E_FAIL;
+
+    switch (last_error)
+    {
+      case ERROR_FILE_NOT_FOUND:
+        hr = STG_E_FILENOTFOUND;
+        break;
+
+      case ERROR_PATH_NOT_FOUND:
+        hr = STG_E_PATHNOTFOUND;
+        break;
+
+      case ERROR_ACCESS_DENIED:
+      case ERROR_WRITE_PROTECT:
+        hr = STG_E_ACCESSDENIED;
+        break;
+
+      case ERROR_SHARING_VIOLATION:
+        hr = STG_E_SHAREVIOLATION;
+        break;
+
+      default:
+        hr = E_FAIL;
+    }
+
+    goto end;
+  }
+
+  /*
+   * Refuse to open the file if it's too small to be a structured storage file
+   * FIXME: verify the file when reading instead of here
+   */
+  length = GetFileSize(hFile, NULL);
+  if (length < 0x100)
+  {
+    CloseHandle(hFile);
+    hr = STG_E_FILEALREADYEXISTS;
+    goto end;
+  }
+
+  /*
+   * Allocate and initialize the new IStorage32object.
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+
+  if (newStorage == 0)
+  {
+    hr = STG_E_INSUFFICIENTMEMORY;
+    goto end;
+  }
+
+  /* if the file's length was zero, initialize the storage */
+  hr = StorageImpl_Construct(
+         newStorage,
+         hFile,
+        pwcsName,
+         NULL,
+         grfMode,
+         TRUE,
+        FALSE );
+
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    /*
+     * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
+     */
+    if(hr == STG_E_INVALIDHEADER)
+       hr = STG_E_FILEALREADYEXISTS;
+    goto end;
+  }
+
+  /* prepare the file name string given in lieu of the root property name */
+  GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL);
+  memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN);
+  newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0';
+
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+
+end:
+  TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
+  return hr;
+}
+
+/******************************************************************************
+ *    StgCreateDocfileOnILockBytes    [OLE32.@]
+ */
+HRESULT WINAPI StgCreateDocfileOnILockBytes(
+      ILockBytes *plkbyt,
+      DWORD grfMode,
+      DWORD reserved,
+      IStorage** ppstgOpen)
+{
+  StorageImpl*   newStorage = 0;
+  HRESULT        hr         = S_OK;
+
+  /*
+   * Validate the parameters
+   */
+  if ((ppstgOpen == 0) || (plkbyt == 0))
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Allocate and initialize the new IStorage object.
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+
+  if (newStorage == 0)
+    return STG_E_INSUFFICIENTMEMORY;
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         0,
+        0,
+         plkbyt,
+         grfMode,
+         FALSE,
+         TRUE);
+
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    return hr;
+  }
+
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+
+  return hr;
+}
+
+/******************************************************************************
+ *    StgOpenStorageOnILockBytes    [OLE32.@]
+ */
+HRESULT WINAPI StgOpenStorageOnILockBytes(
+      ILockBytes *plkbyt,
+      IStorage *pstgPriority,
+      DWORD grfMode,
+      SNB snbExclude,
+      DWORD reserved,
+      IStorage **ppstgOpen)
+{
+  StorageImpl* newStorage = 0;
+  HRESULT        hr = S_OK;
+
+  /*
+   * Perform a sanity check
+   */
+  if ((plkbyt == 0) || (ppstgOpen == 0))
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * Initialize the "out" parameter.
+   */
+  *ppstgOpen = 0;
+
+  /*
+   * Allocate and initialize the new IStorage object.
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+
+  if (newStorage == 0)
+    return STG_E_INSUFFICIENTMEMORY;
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         0,
+         0,
+         plkbyt,
+         grfMode,
+         FALSE,
+         FALSE);
+
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    return hr;
+  }
+
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+
+  return hr;
+}
+
+/******************************************************************************
+ *              StgSetTimes [ole32.@]
+ *              StgSetTimes [OLE32.@]
+ *
+ *
+ */
+HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
+                           FILETIME const *patime, FILETIME const *pmtime)
+{
+  IStorage *stg = NULL;
+  HRESULT r;
+  TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
+
+  r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
+                     0, 0, &stg);
+  if( SUCCEEDED(r) )
+  {
+    r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
+    IStorage_Release(stg);
+  }
+
+  return r;
+}
+
+/******************************************************************************
+ *              StgIsStorageILockBytes        [OLE32.@]
+ *
+ * Determines if the ILockBytes contains a storage object.
+ */
+HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
+{
+  BYTE sig[8];
+  ULARGE_INTEGER offset;
+
+  offset.u.HighPart = 0;
+  offset.u.LowPart  = 0;
+
+  ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
+
+  if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
+    return S_OK;
+
+  return S_FALSE;
+}
+
+/******************************************************************************
+ *              WriteClassStg        [OLE32.@]
+ *
+ * This method will store the specified CLSID in the specified storage object
+ */
+HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
+{
+  HRESULT hRes;
+
+  assert(pStg != 0);
+
+  hRes = IStorage_SetClass(pStg, rclsid);
+
+  return hRes;
+}
+
+/***********************************************************************
+ *    ReadClassStg (OLE32.@)
+ *
+ * This method reads the CLSID previously written to a storage object with the WriteClassStg.
+ */
+HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
+
+    STATSTG pstatstg;
+    HRESULT hRes;
+
+    TRACE("()\n");
+
+    if(pclsid==NULL)
+        return E_POINTER;
+   /*
+    * read a STATSTG structure (contains the clsid) from the storage
+    */
+    hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
+
+    if(SUCCEEDED(hRes))
+        *pclsid=pstatstg.clsid;
+
+    return hRes;
+}
+
+/***********************************************************************
+ *    OleLoadFromStream (OLE32.@)
+ *
+ * This function loads an object from stream
+ */
+HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
+{
+    CLSID      clsid;
+    HRESULT    res;
+    LPPERSISTSTREAM    xstm;
+
+    TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
+
+    res=ReadClassStm(pStm,&clsid);
+    if (!SUCCEEDED(res))
+       return res;
+    res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
+    if (!SUCCEEDED(res))
+       return res;
+    res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
+    if (!SUCCEEDED(res)) {
+       IUnknown_Release((IUnknown*)*ppvObj);
+       return res;
+    }
+    res=IPersistStream_Load(xstm,pStm);
+    IPersistStream_Release(xstm);
+    /* FIXME: all refcounts ok at this point? I think they should be:
+     *                 pStm    : unchanged
+     *         ppvObj  : 1
+     *         xstm    : 0 (released)
+     */
+    return res;
+}
+
+/***********************************************************************
+ *    OleSaveToStream (OLE32.@)
+ *
+ * This function saves an object with the IPersistStream interface on it
+ * to the specified stream.
+ */
+HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
+{
+
+    CLSID clsid;
+    HRESULT res;
+
+    TRACE("(%p,%p)\n",pPStm,pStm);
+
+    res=IPersistStream_GetClassID(pPStm,&clsid);
+
+    if (SUCCEEDED(res)){
+
+        res=WriteClassStm(pStm,&clsid);
+
+        if (SUCCEEDED(res))
+
+            res=IPersistStream_Save(pPStm,pStm,TRUE);
+    }
+
+    TRACE("Finished Save\n");
+    return res;
+}
+
+/****************************************************************************
+ * This method validate a STGM parameter that can contain the values below
+ *
+ * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
+ * The stgm values contained in 0xffff0000 are bitmasks.
+ *
+ * STGM_DIRECT               0x00000000
+ * STGM_TRANSACTED           0x00010000
+ * STGM_SIMPLE               0x08000000
+ *
+ * STGM_READ                 0x00000000
+ * STGM_WRITE                0x00000001
+ * STGM_READWRITE            0x00000002
+ *
+ * STGM_SHARE_DENY_NONE      0x00000040
+ * STGM_SHARE_DENY_READ      0x00000030
+ * STGM_SHARE_DENY_WRITE     0x00000020
+ * STGM_SHARE_EXCLUSIVE      0x00000010
+ *
+ * STGM_PRIORITY             0x00040000
+ * STGM_DELETEONRELEASE      0x04000000
+ *
+ * STGM_CREATE               0x00001000
+ * STGM_CONVERT              0x00020000
+ * STGM_FAILIFTHERE          0x00000000
+ *
+ * STGM_NOSCRATCH            0x00100000
+ * STGM_NOSNAPSHOT           0x00200000
+ */
+static HRESULT validateSTGM(DWORD stgm)
+{
+  DWORD access = STGM_ACCESS_MODE(stgm);
+  DWORD share  = STGM_SHARE_MODE(stgm);
+  DWORD create = STGM_CREATE_MODE(stgm);
+
+  if (stgm&~STGM_KNOWN_FLAGS)
+  {
+    ERR("unknown flags %08lx\n", stgm);
+    return E_FAIL;
+  }
+
+  switch (access)
+  {
+  case STGM_READ:
+  case STGM_WRITE:
+  case STGM_READWRITE:
+    break;
+  default:
+    return E_FAIL;
+  }
+
+  switch (share)
+  {
+  case STGM_SHARE_DENY_NONE:
+  case STGM_SHARE_DENY_READ:
+  case STGM_SHARE_DENY_WRITE:
+  case STGM_SHARE_EXCLUSIVE:
+    break;
+  default:
+    return E_FAIL;
+  }
+
+  switch (create)
+  {
+  case STGM_CREATE:
+  case STGM_FAILIFTHERE:
+    break;
+  default:
+    return E_FAIL;
+  }
+
+  /*
+   * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
+   */
+  if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
+      return E_FAIL;
+
+  /*
+   * STGM_CREATE | STGM_CONVERT
+   * if both are false, STGM_FAILIFTHERE is set to TRUE
+   */
+  if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
+    return E_FAIL;
+
+  /*
+   * STGM_NOSCRATCH requires STGM_TRANSACTED
+   */
+  if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
+    return E_FAIL;
+
+  /*
+   * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
+   * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
+   */
+  if ( (stgm & STGM_NOSNAPSHOT) &&
+        (!(stgm & STGM_TRANSACTED) ||
+         share == STGM_SHARE_EXCLUSIVE ||
+         share == STGM_SHARE_DENY_WRITE) )
+    return E_FAIL;
+
+  return S_OK;
+}
+
+/****************************************************************************
+ *      GetShareModeFromSTGM
+ *
+ * This method will return a share mode flag from a STGM value.
+ * The STGM value is assumed valid.
+ */
+static DWORD GetShareModeFromSTGM(DWORD stgm)
+{
+  switch (STGM_SHARE_MODE(stgm))
+  {
+  case STGM_SHARE_DENY_NONE:
+    return FILE_SHARE_READ | FILE_SHARE_WRITE;
+  case STGM_SHARE_DENY_READ:
+    return FILE_SHARE_WRITE;
+  case STGM_SHARE_DENY_WRITE:
+    return FILE_SHARE_READ;
+  case STGM_SHARE_EXCLUSIVE:
+    return 0;
+  }
+  ERR("Invalid share mode!\n");
+  assert(0);
+  return 0;
+}
+
+/****************************************************************************
+ *      GetAccessModeFromSTGM
+ *
+ * This method will return an access mode flag from a STGM value.
+ * The STGM value is assumed valid.
+ */
+static DWORD GetAccessModeFromSTGM(DWORD stgm)
+{
+  switch (STGM_ACCESS_MODE(stgm))
+  {
+  case STGM_READ:
+    return GENERIC_READ;
+  case STGM_WRITE:
+  case STGM_READWRITE:
+    return GENERIC_READ | GENERIC_WRITE;
+  }
+  ERR("Invalid access mode!\n");
+  assert(0);
+  return 0;
+}
+
+/****************************************************************************
+ *      GetCreationModeFromSTGM
+ *
+ * This method will return a creation mode flag from a STGM value.
+ * The STGM value is assumed valid.
+ */
+static DWORD GetCreationModeFromSTGM(DWORD stgm)
+{
+  switch(STGM_CREATE_MODE(stgm))
+  {
+  case STGM_CREATE:
+    return CREATE_ALWAYS;
+  case STGM_CONVERT:
+    FIXME("STGM_CONVERT not implemented!\n");
+    return CREATE_NEW;
+  case STGM_FAILIFTHERE:
+    return CREATE_NEW;
+  }
+  ERR("Invalid create mode!\n");
+  assert(0);
+  return 0;
+}
+
+
+/*************************************************************************
+ * OLECONVERT_LoadOLE10 [Internal]
+ *
+ * Loads the OLE10 STREAM to memory
+ *
+ * PARAMS
+ *     pOleStream   [I] The OLESTREAM
+ *     pData        [I] Data Structure for the OLESTREAM Data
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
+ *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     Memory allocated for pData must be freed by the caller
+ */
+HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
+{
+       DWORD dwSize;
+       HRESULT hRes = S_OK;
+       int nTryCnt=0;
+       int max_try = 6;
+
+       pData->pData = NULL;
+       pData->pstrOleObjFileName = (CHAR *) NULL;
+
+       for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
+       {
+       /* Get the OleID */
+       dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
+       if(dwSize != sizeof(pData->dwOleID))
+       {
+               hRes = CONVERT10_E_OLESTREAM_GET;
+       }
+       else if(pData->dwOleID != OLESTREAM_ID)
+       {
+               hRes = CONVERT10_E_OLESTREAM_FMT;
+       }
+               else
+               {
+                       hRes = S_OK;
+                       break;
+               }
+       }
+
+       if(hRes == S_OK)
+       {
+               /* Get the TypeID...more info needed for this field */
+               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
+               if(dwSize != sizeof(pData->dwTypeID))
+               {
+                       hRes = CONVERT10_E_OLESTREAM_GET;
+               }
+       }
+       if(hRes == S_OK)
+       {
+               if(pData->dwTypeID != 0)
+               {
+                       /* Get the length of the OleTypeName */
+                       dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
+                       if(dwSize != sizeof(pData->dwOleTypeNameLength))
+                       {
+                               hRes = CONVERT10_E_OLESTREAM_GET;
+                       }
+
+                       if(hRes == S_OK)
+                       {
+                               if(pData->dwOleTypeNameLength > 0)
+                               {
+                                       /* Get the OleTypeName */
+                                       dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
+                                       if(dwSize != pData->dwOleTypeNameLength)
+                                       {
+                                               hRes = CONVERT10_E_OLESTREAM_GET;
+                                       }
+                               }
+                       }
+                       if(bStrem1)
+                       {
+                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
+                               if(dwSize != sizeof(pData->dwOleObjFileNameLength))
+                               {
+                                       hRes = CONVERT10_E_OLESTREAM_GET;
+                               }
+                       if(hRes == S_OK)
+                       {
+                                       if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
+                                               pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
+                                       pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
+                                       if(pData->pstrOleObjFileName)
+                                       {
+                                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
+                                               if(dwSize != pData->dwOleObjFileNameLength)
+                                               {
+                                                       hRes = CONVERT10_E_OLESTREAM_GET;
+                                               }
+                                       }
+                                       else
+                                               hRes = CONVERT10_E_OLESTREAM_GET;
+                               }
+                       }
+                       else
+                       {
+                               /* Get the Width of the Metafile */
+                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
+                               if(dwSize != sizeof(pData->dwMetaFileWidth))
+                               {
+                                       hRes = CONVERT10_E_OLESTREAM_GET;
+                               }
+                       if(hRes == S_OK)
+                       {
+                               /* Get the Height of the Metafile */
+                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
+                               if(dwSize != sizeof(pData->dwMetaFileHeight))
+                               {
+                                       hRes = CONVERT10_E_OLESTREAM_GET;
+                               }
+                       }
+                       }
+                       if(hRes == S_OK)
+                       {
+                               /* Get the Length of the Data */
+                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
+                               if(dwSize != sizeof(pData->dwDataLength))
+                               {
+                                       hRes = CONVERT10_E_OLESTREAM_GET;
+                               }
+                       }
+
+                       if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */
+                       {
+                               if(!bStrem1) /* if it is a second OLE stream data */
+                               {
+                                       pData->dwDataLength -= 8;
+                                       dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
+                                       if(dwSize != sizeof(pData->strUnknown))
+                                       {
+                                               hRes = CONVERT10_E_OLESTREAM_GET;
+                                       }
+                               }
+                       }
+                       if(hRes == S_OK)
+                       {
+                               if(pData->dwDataLength > 0)
+                               {
+                                       pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
+
+                                       /* Get Data (ex. IStorage, Metafile, or BMP) */
+                                       if(pData->pData)
+                                       {
+                                               dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
+                                               if(dwSize != pData->dwDataLength)
+                                               {
+                                                       hRes = CONVERT10_E_OLESTREAM_GET;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               hRes = CONVERT10_E_OLESTREAM_GET;
+                                       }
+                               }
+                       }
+               }
+       }
+       return hRes;
+}
+
+/*************************************************************************
+ * OLECONVERT_SaveOLE10 [Internal]
+ *
+ * Saves the OLE10 STREAM From memory
+ *
+ * PARAMS
+ *     pData        [I] Data Structure for the OLESTREAM Data
+ *     pOleStream   [I] The OLESTREAM to save
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *
+ */
+HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
+{
+    DWORD dwSize;
+    HRESULT hRes = S_OK;
+
+
+   /* Set the OleID */
+    dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
+    if(dwSize != sizeof(pData->dwOleID))
+    {
+        hRes = CONVERT10_E_OLESTREAM_PUT;
+    }
+
+    if(hRes == S_OK)
+    {
+        /* Set the TypeID */
+        dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
+        if(dwSize != sizeof(pData->dwTypeID))
+        {
+            hRes = CONVERT10_E_OLESTREAM_PUT;
+        }
+    }
+
+    if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
+    {
+        /* Set the Length of the OleTypeName */
+        dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
+        if(dwSize != sizeof(pData->dwOleTypeNameLength))
+        {
+            hRes = CONVERT10_E_OLESTREAM_PUT;
+        }
+
+        if(hRes == S_OK)
+        {
+            if(pData->dwOleTypeNameLength > 0)
+            {
+                /* Set the OleTypeName */
+                dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->strOleTypeName, pData->dwOleTypeNameLength);
+                if(dwSize != pData->dwOleTypeNameLength)
+                {
+                    hRes = CONVERT10_E_OLESTREAM_PUT;
+                }
+            }
+        }
+
+        if(hRes == S_OK)
+        {
+            /* Set the width of the Metafile */
+            dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
+            if(dwSize != sizeof(pData->dwMetaFileWidth))
+            {
+                hRes = CONVERT10_E_OLESTREAM_PUT;
+            }
+        }
+
+        if(hRes == S_OK)
+        {
+            /* Set the height of the Metafile */
+            dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
+            if(dwSize != sizeof(pData->dwMetaFileHeight))
+            {
+                hRes = CONVERT10_E_OLESTREAM_PUT;
+            }
+        }
+
+        if(hRes == S_OK)
+        {
+            /* Set the length of the Data */
+            dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
+            if(dwSize != sizeof(pData->dwDataLength))
+            {
+                hRes = CONVERT10_E_OLESTREAM_PUT;
+            }
+        }
+
+        if(hRes == S_OK)
+        {
+            if(pData->dwDataLength > 0)
+            {
+                /* Set the Data (eg. IStorage, Metafile, Bitmap) */
+                dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
+                if(dwSize != pData->dwDataLength)
+                {
+                    hRes = CONVERT10_E_OLESTREAM_PUT;
+                }
+            }
+        }
+    }
+    return hRes;
+}
+
+/*************************************************************************
+ * OLECONVERT_GetOLE20FromOLE10[Internal]
+ *
+ * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
+ * opens it, and copies the content to the dest IStorage for
+ * OleConvertOLESTREAMToIStorage
+ *
+ *
+ * PARAMS
+ *     pDestStorage  [I] The IStorage to copy the data to
+ *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
+ *     nBufferLength [I] The size of the buffer
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *
+ *
+ */
+void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
+{
+    HRESULT hRes;
+    HANDLE hFile;
+    IStorage *pTempStorage;
+    DWORD dwNumOfBytesWritten;
+    WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
+    static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
+
+    /* Create a temp File */
+    GetTempPathW(MAX_PATH, wstrTempDir);
+    GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
+    hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+
+    if(hFile != INVALID_HANDLE_VALUE)
+    {
+        /* Write IStorage Data to File */
+        WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
+        CloseHandle(hFile);
+
+        /* Open and copy temp storage to the Dest Storage */
+        hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
+        if(hRes == S_OK)
+        {
+            hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
+            StorageBaseImpl_Release(pTempStorage);
+        }
+        DeleteFileW(wstrTempFile);
+    }
+}
+
+
+/*************************************************************************
+ * OLECONVERT_WriteOLE20ToBuffer [Internal]
+ *
+ * Saves the OLE10 STREAM From memory
+ *
+ * PARAMS
+ *     pStorage  [I] The Src IStorage to copy
+ *     pData     [I] The Dest Memory to write to.
+ *
+ * RETURNS
+ *     The size in bytes allocated for pData
+ *
+ * NOTES
+ *     Memory allocated for pData must be freed by the caller
+ *
+ *     Used by OleConvertIStorageToOLESTREAM only.
+ *
+ */
+DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
+{
+    HANDLE hFile;
+    HRESULT hRes;
+    DWORD nDataLength = 0;
+    IStorage *pTempStorage;
+    WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
+    static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
+
+    *pData = NULL;
+
+    /* Create temp Storage */
+    GetTempPathW(MAX_PATH, wstrTempDir);
+    GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
+    hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
+
+    if(hRes == S_OK)
+    {
+        /* Copy Src Storage to the Temp Storage */
+        StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
+        StorageBaseImpl_Release(pTempStorage);
+
+        /* Open Temp Storage as a file and copy to memory */
+        hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+        if(hFile != INVALID_HANDLE_VALUE)
+        {
+            nDataLength = GetFileSize(hFile, NULL);
+            *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
+            ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
+            CloseHandle(hFile);
+        }
+        DeleteFileW(wstrTempFile);
+    }
+    return nDataLength;
+}
+
+/*************************************************************************
+ * OLECONVERT_CreateOleStream [Internal]
+ *
+ * Creates the "\001OLE" stream in the IStorage if necessary.
+ *
+ * PARAMS
+ *     pStorage     [I] Dest storage to create the stream in
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     This stream is still unknown, MS Word seems to have extra data
+ *     but since the data is stored in the OLESTREAM there should be
+ *     no need to recreate the stream.  If the stream is manually
+ *     deleted it will create it with this default data.
+ *
+ */
+void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
+    BYTE pOleStreamHeader [] =
+    {
+        0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00
+    };
+
+    /* Create stream if not present */
+    hRes = IStorage_CreateStream(pStorage, wstrStreamName,
+        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+
+    if(hRes == S_OK)
+    {
+        /* Write default Data */
+        hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
+        IStream_Release(pStream);
+    }
+}
+
+/* write a string to a stream, preceded by its length */
+static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string )
+{
+    HRESULT r;
+    LPSTR str;
+    DWORD len = 0;
+
+    if( string )
+        len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
+    r = IStream_Write( stm, &len, sizeof(len), NULL);
+    if( FAILED( r ) )
+        return r;
+    if(len == 0)
+        return r;
+    str = CoTaskMemAlloc( len );
+    WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
+    r = IStream_Write( stm, str, len, NULL);
+    CoTaskMemFree( str );
+    return r;
+}
+
+/* read a string preceded by its length from a stream */
+static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
+{
+    HRESULT r;
+    DWORD len, count = 0;
+    LPSTR str;
+    LPWSTR wstr;
+
+    r = IStream_Read( stm, &len, sizeof(len), &count );
+    if( FAILED( r ) )
+        return r;
+    if( count != sizeof(len) )
+        return E_OUTOFMEMORY;
+
+    TRACE("%ld bytes\n",len);
+    
+    str = CoTaskMemAlloc( len );
+    if( !str )
+        return E_OUTOFMEMORY;
+    count = 0;
+    r = IStream_Read( stm, str, len, &count );
+    if( FAILED( r ) )
+        return r;
+    if( count != len )
+    {
+        CoTaskMemFree( str );
+        return E_OUTOFMEMORY;
+    }
+
+    TRACE("Read string %s\n",debugstr_an(str,len));
+
+    len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
+    wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
+    if( wstr )
+         MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
+    CoTaskMemFree( str );
+
+    *string = wstr;
+
+    return r;
+}
+
+
+static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
+    LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
+{
+    IStream *pstm;
+    HRESULT r = S_OK;
+    static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
+
+    static const BYTE unknown1[12] =
+       { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
+         0xFF, 0xFF, 0xFF, 0xFF};
+    static const BYTE unknown2[16] =
+       { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+    TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
+           debugstr_w(lpszUserType), debugstr_w(szClipName),
+           debugstr_w(szProgIDName));
+
+    /*  Create a CompObj stream if it doesn't exist */
+    r = IStorage_CreateStream(pstg, szwStreamName,
+        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
+    if( FAILED (r) )
+        return r;
+
+    /* Write CompObj Structure to stream */
+    r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
+
+    if( SUCCEEDED( r ) )
+        r = WriteClassStm( pstm, clsid );
+
+    if( SUCCEEDED( r ) )
+        r = STREAM_WriteString( pstm, lpszUserType );
+    if( SUCCEEDED( r ) )
+        r = STREAM_WriteString( pstm, szClipName );
+    if( SUCCEEDED( r ) )
+        r = STREAM_WriteString( pstm, szProgIDName );
+    if( SUCCEEDED( r ) )
+        r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
+
+    IStream_Release( pstm );
+
+    return r;
+}
+
+/***********************************************************************
+ *               WriteFmtUserTypeStg (OLE32.@)
+ */
+HRESULT WINAPI WriteFmtUserTypeStg(
+         LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
+{
+    HRESULT r;
+    WCHAR szwClipName[0x40];
+    CLSID clsid = CLSID_NULL;
+    LPWSTR wstrProgID = NULL;
+    DWORD n;
+
+    TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
+
+    /* get the clipboard format name */
+    n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) );
+    szwClipName[n]=0;
+
+    TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
+
+    /* FIXME: There's room to save a CLSID and its ProgID, but
+       the CLSID is not looked up in the registry and in all the
+       tests I wrote it was CLSID_NULL.  Where does it come from?
+    */
+
+    /* get the real program ID.  This may fail, but that's fine */
+    ProgIDFromCLSID(&clsid, &wstrProgID);
+
+    TRACE("progid is %s\n",debugstr_w(wstrProgID));
+
+    r = STORAGE_WriteCompObj( pstg, &clsid, 
+                              lpszUserType, szwClipName, wstrProgID );
+
+    CoTaskMemFree(wstrProgID);
+
+    return r;
+}
+
+
+/******************************************************************************
+ *              ReadFmtUserTypeStg        [OLE32.@]
+ */
+HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
+{
+    HRESULT r;
+    IStream *stm = 0;
+    static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 };
+    unsigned char unknown1[12];
+    unsigned char unknown2[16];
+    DWORD count;
+    LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
+    CLSID clsid;
+
+    TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
+
+    r = IStorage_OpenStream( pstg, szCompObj, NULL, 
+                    STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
+    if( FAILED ( r ) )
+    {
+        WARN("Failed to open stream r = %08lx\n", r);
+        return r;
+    }
+
+    /* read the various parts of the structure */
+    r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
+    if( FAILED( r ) || ( count != sizeof(unknown1) ) )
+        goto end;
+    r = ReadClassStm( stm, &clsid );
+    if( FAILED( r ) )
+        goto end;
+
+    r = STREAM_ReadString( stm, &szCLSIDName );
+    if( FAILED( r ) )
+        goto end;
+
+    r = STREAM_ReadString( stm, &szOleTypeName );
+    if( FAILED( r ) )
+        goto end;
+
+    r = STREAM_ReadString( stm, &szProgIDName );
+    if( FAILED( r ) )
+        goto end;
+
+    r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
+    if( FAILED( r ) || ( count != sizeof(unknown2) ) )
+        goto end;
+
+    /* ok, success... now we just need to store what we found */
+    if( pcf )
+        *pcf = RegisterClipboardFormatW( szOleTypeName );
+    CoTaskMemFree( szOleTypeName );
+
+    if( lplpszUserType )
+        *lplpszUserType = szCLSIDName;
+    CoTaskMemFree( szProgIDName );
+
+end:
+    IStream_Release( stm );
+
+    return r;
+}
+
+
+/*************************************************************************
+ * OLECONVERT_CreateCompObjStream [Internal]
+ *
+ * Creates a "\001CompObj" is the destination IStorage if necessary.
+ *
+ * PARAMS
+ *     pStorage       [I] The dest IStorage to create the CompObj Stream
+ *                        if necessary.
+ *     strOleTypeName [I] The ProgID
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     The stream data is stored in the OLESTREAM and there should be
+ *     no need to recreate the stream.  If the stream is manually
+ *     deleted it will attempt to create it by querying the registry.
+ *
+ *
+ */
+HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
+{
+    IStream *pStream;
+    HRESULT hStorageRes, hRes = S_OK;
+    OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
+    static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
+    WCHAR bufferW[OLESTREAM_MAX_STR_LEN];
+
+    BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
+    BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
+
+    /* Initialize the CompObj structure */
+    memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
+    memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
+    memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
+
+
+    /*  Create a CompObj stream if it doesn't exist */
+    hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
+        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+    if(hStorageRes == S_OK)
+    {
+        /* copy the OleTypeName to the compobj struct */
+        IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
+        strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
+
+        /* copy the OleTypeName to the compobj struct */
+        /* Note: in the test made, these were Identical      */
+        IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
+        strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
+
+        /* Get the CLSID */
+        MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
+                             bufferW, OLESTREAM_MAX_STR_LEN );
+        hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
+
+        if(hRes == S_OK)
+        {
+            HKEY hKey;
+            LONG hErr;
+            /* Get the CLSID Default Name from the Registry */
+            hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
+            if(hErr == ERROR_SUCCESS)
+            {
+                char strTemp[OLESTREAM_MAX_STR_LEN];
+                IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
+                hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength));
+                if(hErr == ERROR_SUCCESS)
+                {
+                    strcpy(IStorageCompObj.strCLSIDName, strTemp);
+                }
+                RegCloseKey(hKey);
+            }
+        }
+
+        /* Write CompObj Structure to stream */
+        hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
+
+        WriteClassStm(pStream,&(IStorageCompObj.clsid));
+
+        hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
+        if(IStorageCompObj.dwCLSIDNameLength > 0)
+        {
+            hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
+        }
+        hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
+        if(IStorageCompObj.dwOleTypeNameLength > 0)
+        {
+            hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
+        }
+        hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
+        if(IStorageCompObj.dwProgIDNameLength > 0)
+        {
+            hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
+        }
+        hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
+        IStream_Release(pStream);
+    }
+    return hRes;
+}
+
+
+/*************************************************************************
+ * OLECONVERT_CreateOlePresStream[Internal]
+ *
+ * Creates the "\002OlePres000" Stream with the Metafile data
+ *
+ * PARAMS
+ *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
+ *     dwExtentX    [I] Width of the Metafile
+ *     dwExtentY    [I] Height of the Metafile
+ *     pData        [I] Metafile data
+ *     dwDataLength [I] Size of the Metafile data
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ */
+void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
+    BYTE pOlePresStreamHeader [] =
+    {
+        0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
+        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00
+    };
+
+    BYTE pOlePresStreamHeaderEmpty [] =
+    {
+        0x00, 0x00, 0x00, 0x00,
+        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00
+    };
+
+    /* Create the OlePres000 Stream */
+    hRes = IStorage_CreateStream(pStorage, wstrStreamName,
+        STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+
+    if(hRes == S_OK)
+    {
+        DWORD nHeaderSize;
+        OLECONVERT_ISTORAGE_OLEPRES OlePres;
+
+        memset(&OlePres, 0, sizeof(OlePres));
+        /* Do we have any metafile data to save */
+        if(dwDataLength > 0)
+        {
+            memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
+            nHeaderSize = sizeof(pOlePresStreamHeader);
+        }
+        else
+        {
+            memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
+            nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
+        }
+        /* Set width and height of the metafile */
+        OlePres.dwExtentX = dwExtentX;
+        OlePres.dwExtentY = -dwExtentY;
+
+        /* Set Data and Length */
+        if(dwDataLength > sizeof(METAFILEPICT16))
+        {
+            OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
+            OlePres.pData = &(pData[8]);
+        }
+        /* Save OlePres000 Data to Stream */
+        hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
+        hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
+        hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
+        hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
+        if(OlePres.dwSize > 0)
+        {
+            hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
+        }
+        IStream_Release(pStream);
+    }
+}
+
+/*************************************************************************
+ * OLECONVERT_CreateOle10NativeStream [Internal]
+ *
+ * Creates the "\001Ole10Native" Stream (should contain a BMP)
+ *
+ * PARAMS
+ *     pStorage     [I] Dest storage to create the stream in
+ *     pData        [I] Ole10 Native Data (ex. bmp)
+ *     dwDataLength [I] Size of the Ole10 Native Data
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     Might need to verify the data and return appropriate error message
+ *
+ */
+void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
+
+    /* Create the Ole10Native Stream */
+    hRes = IStorage_CreateStream(pStorage, wstrStreamName,
+        STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+
+    if(hRes == S_OK)
+    {
+        /* Write info to stream */
+        hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
+        hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
+        IStream_Release(pStream);
+    }
+
+}
+
+/*************************************************************************
+ * OLECONVERT_GetOLE10ProgID [Internal]
+ *
+ * Finds the ProgID (or OleTypeID) from the IStorage
+ *
+ * PARAMS
+ *     pStorage        [I] The Src IStorage to get the ProgID
+ *     strProgID       [I] the ProgID string to get
+ *     dwSize          [I] the size of the string
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *
+ *
+ */
+HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    LARGE_INTEGER iSeekPos;
+    OLECONVERT_ISTORAGE_COMPOBJ CompObj;
+    static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
+
+    /* Open the CompObj Stream */
+    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
+        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+    if(hRes == S_OK)
+    {
+
+        /*Get the OleType from the CompObj Stream */
+        iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
+        iSeekPos.u.HighPart = 0;
+
+        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
+        IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
+        iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength;
+        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
+        IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
+        iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength;
+        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
+
+        IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
+        if(*dwSize > 0)
+        {
+            IStream_Read(pStream, strProgID, *dwSize, NULL);
+        }
+        IStream_Release(pStream);
+    }
+    else
+    {
+        STATSTG stat;
+        LPOLESTR wstrProgID;
+
+        /* Get the OleType from the registry */
+        REFCLSID clsid = &(stat.clsid);
+        IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
+        hRes = ProgIDFromCLSID(clsid, &wstrProgID);
+        if(hRes == S_OK)
+        {
+            *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
+        }
+
+    }
+    return hRes;
+}
+
+/*************************************************************************
+ * OLECONVERT_GetOle10PresData [Internal]
+ *
+ * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
+ *
+ * PARAMS
+ *     pStorage     [I] Src IStroage
+ *     pOleStream   [I] Dest OleStream Mem Struct
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *
+ *     Memory allocated for pData must be freed by the caller
+ *
+ *
+ */
+void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+{
+
+    HRESULT hRes;
+    IStream *pStream;
+    static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
+
+    /* Initialize Default data for OLESTREAM */
+    pOleStreamData[0].dwOleID = OLESTREAM_ID;
+    pOleStreamData[0].dwTypeID = 2;
+    pOleStreamData[1].dwOleID = OLESTREAM_ID;
+    pOleStreamData[1].dwTypeID = 0;
+    pOleStreamData[0].dwMetaFileWidth = 0;
+    pOleStreamData[0].dwMetaFileHeight = 0;
+    pOleStreamData[0].pData = NULL;
+    pOleStreamData[1].pData = NULL;
+
+    /* Open Ole10Native Stream */
+    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
+        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+    if(hRes == S_OK)
+    {
+
+        /* Read Size and Data */
+        IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
+        if(pOleStreamData->dwDataLength > 0)
+        {
+            pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
+            IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
+        }
+        IStream_Release(pStream);
+    }
+
+}
+
+
+/*************************************************************************
+ * OLECONVERT_GetOle20PresData[Internal]
+ *
+ * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
+ *
+ * PARAMS
+ *     pStorage         [I] Src IStroage
+ *     pOleStreamData   [I] Dest OleStream Mem Struct
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *
+ *     Memory allocated for pData must be freed by the caller
+ */
+void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    OLECONVERT_ISTORAGE_OLEPRES olePress;
+    static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
+
+    /* Initialize Default data for OLESTREAM */
+    pOleStreamData[0].dwOleID = OLESTREAM_ID;
+    pOleStreamData[0].dwTypeID = 2;
+    pOleStreamData[0].dwMetaFileWidth = 0;
+    pOleStreamData[0].dwMetaFileHeight = 0;
+    pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
+    pOleStreamData[1].dwOleID = OLESTREAM_ID;
+    pOleStreamData[1].dwTypeID = 0;
+    pOleStreamData[1].dwOleTypeNameLength = 0;
+    pOleStreamData[1].strOleTypeName[0] = 0;
+    pOleStreamData[1].dwMetaFileWidth = 0;
+    pOleStreamData[1].dwMetaFileHeight = 0;
+    pOleStreamData[1].pData = NULL;
+    pOleStreamData[1].dwDataLength = 0;
+
+
+    /* Open OlePress000 stream */
+    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
+        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+    if(hRes == S_OK)
+    {
+        LARGE_INTEGER iSeekPos;
+        METAFILEPICT16 MetaFilePict;
+        static const char strMetafilePictName[] = "METAFILEPICT";
+
+        /* Set the TypeID for a Metafile */
+        pOleStreamData[1].dwTypeID = 5;
+
+        /* Set the OleTypeName to Metafile */
+        pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
+        strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
+
+        iSeekPos.u.HighPart = 0;
+        iSeekPos.u.LowPart = sizeof(olePress.byUnknown1);
+
+        /* Get Presentation Data */
+        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
+        IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
+        IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
+        IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
+
+        /*Set width and Height */
+        pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
+        pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
+        if(olePress.dwSize > 0)
+        {
+            /* Set Length */
+            pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
+
+            /* Set MetaFilePict struct */
+            MetaFilePict.mm = 8;
+            MetaFilePict.xExt = olePress.dwExtentX;
+            MetaFilePict.yExt = olePress.dwExtentY;
+            MetaFilePict.hMF = 0;
+
+            /* Get Metafile Data */
+            pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
+            memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
+            IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
+        }
+        IStream_Release(pStream);
+    }
+}
+
+/*************************************************************************
+ * OleConvertOLESTREAMToIStorage [OLE32.@]
+ *
+ * Read info on MSDN
+ *
+ * TODO
+ *      DVTARGETDEVICE paramenter is not handled
+ *      Still unsure of some mem fields for OLE 10 Stream
+ *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
+ *      and "\001OLE" streams
+ *
+ */
+HRESULT WINAPI OleConvertOLESTREAMToIStorage (
+    LPOLESTREAM pOleStream,
+    LPSTORAGE pstg,
+    const DVTARGETDEVICE* ptd)
+{
+    int i;
+    HRESULT hRes=S_OK;
+    OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
+
+    memset(pOleStreamData, 0, sizeof(pOleStreamData));
+
+    if(ptd != NULL)
+    {
+        FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
+    }
+
+    if(pstg == NULL || pOleStream == NULL)
+    {
+        hRes = E_INVALIDARG;
+    }
+
+    if(hRes == S_OK)
+    {
+        /* Load the OLESTREAM to Memory */
+        hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
+    }
+
+    if(hRes == S_OK)
+    {
+        /* Load the OLESTREAM to Memory (part 2)*/
+        hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
+    }
+
+    if(hRes == S_OK)
+    {
+
+        if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
+        {
+            /* Do we have the IStorage Data in the OLESTREAM */
+            if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
+            {
+                OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
+                OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
+            }
+            else
+            {
+                /* It must be an original OLE 1.0 source */
+                OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
+            }
+        }
+        else
+        {
+            /* It must be an original OLE 1.0 source */
+            OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
+        }
+
+        /* Create CompObj Stream if necessary */
+        hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
+        if(hRes == S_OK)
+        {
+            /*Create the Ole Stream if necessary */
+            OLECONVERT_CreateOleStream(pstg);
+        }
+    }
+
+
+    /* Free allocated memory */
+    for(i=0; i < 2; i++)
+    {
+        HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
+        HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
+        pOleStreamData[i].pstrOleObjFileName = NULL;
+    }
+    return hRes;
+}
+
+/*************************************************************************
+ * OleConvertIStorageToOLESTREAM [OLE32.@]
+ *
+ * Read info on MSDN
+ *
+ * Read info on MSDN
+ *
+ * TODO
+ *      Still unsure of some mem fields for OLE 10 Stream
+ *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
+ *      and "\001OLE" streams.
+ *
+ */
+HRESULT WINAPI OleConvertIStorageToOLESTREAM (
+    LPSTORAGE pstg,
+    LPOLESTREAM pOleStream)
+{
+    int i;
+    HRESULT hRes = S_OK;
+    IStream *pStream;
+    OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
+    static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
+
+
+    memset(pOleStreamData, 0, sizeof(pOleStreamData));
+
+    if(pstg == NULL || pOleStream == NULL)
+    {
+        hRes = E_INVALIDARG;
+    }
+    if(hRes == S_OK)
+    {
+        /* Get the ProgID */
+        pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
+        hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
+    }
+    if(hRes == S_OK)
+    {
+        /* Was it originally Ole10 */
+        hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
+        if(hRes == S_OK)
+        {
+            IStream_Release(pStream);
+            /* Get Presentation Data for Ole10Native */
+            OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
+        }
+        else
+        {
+            /* Get Presentation Data (OLE20) */
+            OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
+        }
+
+        /* Save OLESTREAM */
+        hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
+        if(hRes == S_OK)
+        {
+            hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
+        }
+
+    }
+
+    /* Free allocated memory */
+    for(i=0; i < 2; i++)
+    {
+        HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
+    }
+
+    return hRes;
+}
+
+/***********************************************************************
+ *             GetConvertStg (OLE32.@)
+ */
+HRESULT WINAPI GetConvertStg(IStorage *stg) {
+    FIXME("unimplemented stub!\n");
+    return E_FAIL;
+}
+
+/******************************************************************************
+ * StgIsStorageFile [OLE32.@]
+ */
+HRESULT WINAPI
+StgIsStorageFile(LPCOLESTR fn)
+{
+       HANDLE          hf;
+       BYTE            magic[8];
+       DWORD           bytes_read;
+
+       TRACE("(\'%s\')\n", debugstr_w(fn));
+       hf = CreateFileW(fn, GENERIC_READ,
+                        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+
+       if (hf == INVALID_HANDLE_VALUE)
+               return STG_E_FILENOTFOUND;
+
+       if (!ReadFile(hf, magic, 8, &bytes_read, NULL))
+       {
+               WARN(" unable to read file\n");
+               CloseHandle(hf);
+               return S_FALSE;
+       }
+
+       CloseHandle(hf);
+
+       if (bytes_read != 8) {
+               WARN(" too short\n");
+               return S_FALSE;
+       }
+
+       if (!memcmp(magic,STORAGE_magic,8)) {
+               WARN(" -> YES\n");
+               return S_OK;
+       }
+
+       WARN(" -> Invalid header.\n");
+       return S_FALSE;
+}