rpcrt4: Fix bug calculating union switch type.
[wine] / dlls / ole32 / storage32.c
index c4afa65..bda5bdc 100644 (file)
@@ -8,6 +8,7 @@
  * 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
  *
  * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * NOTES
+ *  The compound file implementation of IStorage used for create
+ *  and manage substorages and streams within a storage object
+ *  residing in a compound file object.
+ *
+ * MSDN
+ *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/istorage_compound_file_implementation.asp
  */
 
 #include <assert.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
 
+/*
+ * These are signatures to detect the type of Document file.
+ */
+static const BYTE STORAGE_magic[8]    ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
+static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
+
 static const char rootPropertyName[] = "Root Entry";
 
+/****************************************************************************
+ * Storage32InternalImpl definitions.
+ *
+ * Definition of the implementation structure for the IStorage32 interface.
+ * This one implements the IStorage32 interface for storage that are
+ * inside another storage.
+ */
+struct StorageInternalImpl
+{
+  struct StorageBaseImpl base;
+  /*
+   * There is no specific data for this class.
+   */
+};
+typedef struct StorageInternalImpl StorageInternalImpl;
+
+/* Method definitions for the Storage32InternalImpl class. */
+static StorageInternalImpl* StorageInternalImpl_Construct(StorageImpl* ancestorStorage,
+                                                          DWORD openFlags, ULONG rootTropertyIndex);
+static void StorageImpl_Destroy(StorageBaseImpl* iface);
+static BOOL StorageImpl_ReadBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer);
+static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer);
+static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG nextBlock);
+static HRESULT StorageImpl_LoadFileHeader(StorageImpl* This);
+static void StorageImpl_SaveFileHeader(StorageImpl* This);
+
+static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex);
+static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This);
+static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex);
+static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex);
+static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex);
+
+static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This);
+static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This);
+static ULONG BlockChainStream_GetCount(BlockChainStream* This);
+
+static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This);
+static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This,
+    ULONG blockIndex, ULONG offset, DWORD value);
+static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl*  This,
+    ULONG blockIndex, ULONG offset, DWORD* value);
 
 /* OLESTREAM memory structure to use for Get and Put Routines */
 /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
@@ -157,77 +210,81 @@ static DWORD GetShareModeFromSTGM(DWORD stgm);
 static DWORD GetAccessModeFromSTGM(DWORD stgm);
 static DWORD GetCreationModeFromSTGM(DWORD stgm);
 
-/*
- * 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
-};
+extern const IPropertySetStorageVtbl IPropertySetStorage_Vtbl;
 
-/*
- * 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
-};
 
-/*
- * Virtual function table for the IEnumSTATSTGImpl class.
+/****************************************************************************
+ * IEnumSTATSTGImpl definitions.
+ *
+ * Definition of the implementation structure for the IEnumSTATSTGImpl interface.
+ * This class allows iterating through the content of a storage and to find
+ * specific items inside it.
  */
-static IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
+struct IEnumSTATSTGImpl
 {
-    IEnumSTATSTGImpl_QueryInterface,
-    IEnumSTATSTGImpl_AddRef,
-    IEnumSTATSTGImpl_Release,
-    IEnumSTATSTGImpl_Next,
-    IEnumSTATSTGImpl_Skip,
-    IEnumSTATSTGImpl_Reset,
-    IEnumSTATSTGImpl_Clone
+  const IEnumSTATSTGVtbl *lpVtbl;    /* Needs to be the first item in the struct
+                               * since we want to cast this in an IEnumSTATSTG pointer */
+
+  LONG           ref;                   /* Reference count */
+  StorageImpl*   parentStorage;         /* Reference to the parent storage */
+  ULONG          firstPropertyNode;     /* Index of the root of the storage to enumerate */
+
+  /*
+   * The current implementation of the IEnumSTATSTGImpl class uses a stack
+   * to walk the property sets to get the content of a storage. This stack
+   * is implemented by the following 3 data members
+   */
+  ULONG          stackSize;
+  ULONG          stackMaxSize;
+  ULONG*         stackToVisit;
+
+#define ENUMSTATSGT_SIZE_INCREMENT 10
 };
 
 
+static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageImpl* This, ULONG firstPropertyNode);
+static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This);
+static void IEnumSTATSTGImpl_PushSearchNode(IEnumSTATSTGImpl* This, ULONG nodeToPush);
+static ULONG IEnumSTATSTGImpl_PopSearchNode(IEnumSTATSTGImpl* This, BOOL remove);
+static ULONG IEnumSTATSTGImpl_FindProperty(IEnumSTATSTGImpl* This, const OLECHAR* lpszPropName,
+                                           StgProperty* buffer);
+static INT IEnumSTATSTGImpl_FindParentProperty(IEnumSTATSTGImpl *This, ULONG childProperty,
+                                               StgProperty *currentProperty, ULONG *propertyId);
+
+/************************************************************************
+** Block Functions
+*/
 
+static ULONG BLOCK_GetBigBlockOffset(ULONG index)
+{
+    if (index == 0xffffffff)
+        index = 0;
+    else
+        index ++;
 
+    return index * BIG_BLOCK_SIZE;
+}
 
 /************************************************************************
 ** Storage32BaseImpl implementatiion
 */
+static HRESULT StorageImpl_ReadAt(StorageImpl* This,
+  ULARGE_INTEGER offset,
+  void*          buffer,
+  ULONG          size,
+  ULONG*         bytesRead)
+{
+    return BIGBLOCKFILE_ReadAt(This->bigBlockFile,offset,buffer,size,bytesRead);
+}
+
+static HRESULT StorageImpl_WriteAt(StorageImpl* This,
+  ULARGE_INTEGER offset,
+  void*          buffer,
+  const ULONG    size,
+  ULONG*         bytesWritten)
+{
+    return BIGBLOCKFILE_WriteAt(This->bigBlockFile,offset,buffer,size,bytesWritten);
+}
 
 /************************************************************************
  * Storage32BaseImpl_QueryInterface (IUnknown)
@@ -237,7 +294,7 @@ static IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
  *
  * See Windows documentation for more details on IUnknown methods.
  */
-HRESULT WINAPI StorageBaseImpl_QueryInterface(
+static HRESULT WINAPI StorageBaseImpl_QueryInterface(
   IStorage*        iface,
   REFIID             riid,
   void**             ppvObject)
@@ -257,13 +314,14 @@ HRESULT WINAPI StorageBaseImpl_QueryInterface(
   /*
    * Compare the riid with the interface IDs implemented by this object.
    */
-  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
+  if (IsEqualGUID(&IID_IUnknown, riid) ||
+      IsEqualGUID(&IID_IStorage, riid))
   {
     *ppvObject = (IStorage*)This;
   }
-  else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
+  else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
   {
-    *ppvObject = (IStorage*)This;
+    *ppvObject = (IStorage*)&This->pssVtbl;
   }
 
   /*
@@ -276,7 +334,7 @@ HRESULT WINAPI StorageBaseImpl_QueryInterface(
    * Query Interface always increases the reference count by one when it is
    * successful
    */
-  StorageBaseImpl_AddRef(iface);
+  IStorage_AddRef(iface);
 
   return S_OK;
 }
@@ -289,11 +347,15 @@ HRESULT WINAPI StorageBaseImpl_QueryInterface(
  *
  * See Windows documentation for more details on IUnknown methods.
  */
-ULONG WINAPI StorageBaseImpl_AddRef(
+static ULONG WINAPI StorageBaseImpl_AddRef(
             IStorage* iface)
 {
   StorageBaseImpl *This = (StorageBaseImpl *)iface;
-  return InterlockedIncrement(&This->ref);
+  ULONG ref = InterlockedIncrement(&This->ref);
+
+  TRACE("(%p) AddRef to %d\n", This, ref);
+
+  return ref;
 }
 
 /************************************************************************
@@ -304,7 +366,7 @@ ULONG WINAPI StorageBaseImpl_AddRef(
  *
  * See Windows documentation for more details on IUnknown methods.
  */
-ULONG WINAPI StorageBaseImpl_Release(
+static ULONG WINAPI StorageBaseImpl_Release(
       IStorage* iface)
 {
   StorageBaseImpl *This = (StorageBaseImpl *)iface;
@@ -313,6 +375,8 @@ ULONG WINAPI StorageBaseImpl_Release(
    */
   ULONG ref = InterlockedDecrement(&This->ref);
 
+  TRACE("(%p) ReleaseRef to %d\n", This, ref);
+
   /*
    * If the reference count goes down to 0, perform suicide.
    */
@@ -336,7 +400,7 @@ ULONG WINAPI StorageBaseImpl_Release(
  *
  * See Windows documentation for more details on IStorage methods.
  */
-HRESULT WINAPI StorageBaseImpl_OpenStream(
+static HRESULT WINAPI StorageBaseImpl_OpenStream(
   IStorage*        iface,
   const OLECHAR*   pwcsName,  /* [string][in] */
   void*            reserved1, /* [unique][in] */
@@ -351,7 +415,7 @@ HRESULT WINAPI StorageBaseImpl_OpenStream(
   ULONG             foundPropertyIndex;
   HRESULT           res = STG_E_UNKNOWN;
 
-  TRACE("(%p, %s, %p, %lx, %ld, %p)\n",
+  TRACE("(%p, %s, %p, %x, %d, %p)\n",
        iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
 
   /*
@@ -371,7 +435,8 @@ HRESULT WINAPI StorageBaseImpl_OpenStream(
   /*
    * Validate the STGM flags
    */
-  if ( FAILED( validateSTGM(grfMode) ))
+  if ( FAILED( validateSTGM(grfMode) ) ||
+       STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
   {
     res = STG_E_INVALIDFLAG;
     goto end;
@@ -380,14 +445,24 @@ HRESULT WINAPI StorageBaseImpl_OpenStream(
   /*
    * As documented.
    */
-  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
-        (grfMode & STGM_DELETEONRELEASE) ||
-        (grfMode & STGM_TRANSACTED) )
+  if ( (grfMode & STGM_DELETEONRELEASE) || (grfMode & STGM_TRANSACTED) )
   {
     res = STG_E_INVALIDFUNCTION;
     goto end;
   }
 
+  /*
+   * Check that we're compatible with the parent's storage mode, but
+   * only if we are not in transacted mode
+   */
+  if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) {
+    if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
+    {
+      res = STG_E_ACCESSDENIED;
+      goto end;
+    }
+  }
+
   /*
    * Create a property enumeration to search the properties
    */
@@ -425,7 +500,7 @@ HRESULT WINAPI StorageBaseImpl_OpenStream(
        * Since we are returning a pointer to the interface, we have to
        * nail down the reference.
        */
-      StgStreamImpl_AddRef(*ppstm);
+      IStream_AddRef(*ppstm);
 
       res = S_OK;
       goto end;
@@ -440,7 +515,7 @@ HRESULT WINAPI StorageBaseImpl_OpenStream(
 end:
   if (res == S_OK)
     TRACE("<-- IStream %p\n", *ppstm);
-  TRACE("<-- %08lx\n", res);
+  TRACE("<-- %08x\n", res);
   return res;
 }
 
@@ -451,7 +526,7 @@ end:
  *
  * See Windows documentation for more details on IStorage methods.
  */
-HRESULT WINAPI StorageBaseImpl_OpenStorage(
+static HRESULT WINAPI StorageBaseImpl_OpenStorage(
   IStorage*        iface,
   const OLECHAR*   pwcsName,      /* [string][unique][in] */
   IStorage*        pstgPriority,  /* [unique][in] */
@@ -467,7 +542,7 @@ HRESULT WINAPI StorageBaseImpl_OpenStorage(
   ULONG                  foundPropertyIndex;
   HRESULT                res = STG_E_UNKNOWN;
 
-  TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",
+  TRACE("(%p, %s, %p, %x, %p, %d, %p)\n",
        iface, debugstr_w(pwcsName), pstgPriority,
        grfMode, snbExclude, reserved, ppstg);
 
@@ -499,7 +574,7 @@ HRESULT WINAPI StorageBaseImpl_OpenStorage(
   /*
    * As documented.
    */
-  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
+  if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||
         (grfMode & STGM_DELETEONRELEASE) ||
         (grfMode & STGM_PRIORITY) )
   {
@@ -507,6 +582,18 @@ HRESULT WINAPI StorageBaseImpl_OpenStorage(
     goto end;
   }
 
+  /*
+   * Check that we're compatible with the parent's storage mode,
+   * but only if we are not transacted
+   */
+  if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) {
+    if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
+    {
+      res = STG_E_ACCESSDENIED;
+      goto end;
+    }
+  }
+
   /*
    * Initialize the out parameter
    */
@@ -543,6 +630,7 @@ HRESULT WINAPI StorageBaseImpl_OpenStorage(
      */
     newStorage = StorageInternalImpl_Construct(
                    This->ancestorStorage,
+                   grfMode,
                    foundPropertyIndex);
 
     if (newStorage != 0)
@@ -566,7 +654,7 @@ HRESULT WINAPI StorageBaseImpl_OpenStorage(
   res = STG_E_FILENOTFOUND;
 
 end:
-  TRACE("<-- %08lx\n", res);
+  TRACE("<-- %08x\n", res);
   return res;
 }
 
@@ -578,7 +666,7 @@ end:
  *
  * See Windows documentation for more details on IStorage methods.
  */
-HRESULT WINAPI StorageBaseImpl_EnumElements(
+static HRESULT WINAPI StorageBaseImpl_EnumElements(
   IStorage*       iface,
   DWORD           reserved1, /* [in] */
   void*           reserved2, /* [size_is][unique][in] */
@@ -588,7 +676,7 @@ HRESULT WINAPI StorageBaseImpl_EnumElements(
   StorageBaseImpl *This = (StorageBaseImpl *)iface;
   IEnumSTATSTGImpl* newEnum;
 
-  TRACE("(%p, %ld, %p, %ld, %p)\n",
+  TRACE("(%p, %d, %p, %d, %p)\n",
        iface, reserved1, reserved2, reserved3, ppenum);
 
   /*
@@ -612,7 +700,7 @@ HRESULT WINAPI StorageBaseImpl_EnumElements(
      * Don't forget to nail down a reference to the new object before
      * returning it.
      */
-    IEnumSTATSTGImpl_AddRef(*ppenum);
+    IEnumSTATSTG_AddRef(*ppenum);
 
     return S_OK;
   }
@@ -627,7 +715,7 @@ HRESULT WINAPI StorageBaseImpl_EnumElements(
  *
  * See Windows documentation for more details on IStorage methods.
  */
-HRESULT WINAPI StorageBaseImpl_Stat(
+static HRESULT WINAPI StorageBaseImpl_Stat(
   IStorage*        iface,
   STATSTG*         pstatstg,     /* [out] */
   DWORD            grfStatFlag)  /* [in] */
@@ -637,7 +725,7 @@ HRESULT WINAPI StorageBaseImpl_Stat(
   BOOL           readSuccessful;
   HRESULT        res = STG_E_UNKNOWN;
 
-  TRACE("(%p, %p, %lx)\n",
+  TRACE("(%p, %p, %x)\n",
        iface, pstatstg, grfStatFlag);
 
   /*
@@ -664,6 +752,9 @@ HRESULT WINAPI StorageBaseImpl_Stat(
       &curProperty,
       grfStatFlag);
 
+    pstatstg->grfMode = This->openFlags;
+    pstatstg->grfStateBits = This->stateBits;
+
     res = S_OK;
     goto end;
   }
@@ -673,9 +764,9 @@ HRESULT WINAPI StorageBaseImpl_Stat(
 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("<-- STATSTG: pwcsName: %s, type: %d, cbSize.Low/High: %d/%d, grfMode: %08x, grfLocksSupported: %d, grfStateBits: %08x\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);
   }
-  TRACE("<-- %08lx\n", res);
+  TRACE("<-- %08x\n", res);
   return res;
 }
 
@@ -690,7 +781,7 @@ end:
  *    of the deleted StgProperty object setting it with the new name and to
  *    perform a DestroyElement of the old StgProperty.
  */
-HRESULT WINAPI StorageBaseImpl_RenameElement(
+static HRESULT WINAPI StorageBaseImpl_RenameElement(
             IStorage*        iface,
             const OLECHAR*   pwcsOldName,  /* [in] */
             const OLECHAR*   pwcsNewName)  /* [in] */
@@ -725,7 +816,7 @@ HRESULT WINAPI StorageBaseImpl_RenameElement(
     return STG_E_FILEALREADYEXISTS;
   }
 
-  IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
+  IEnumSTATSTG_Reset((IEnumSTATSTG*)propertyEnumeration);
 
   /*
    * Search the enumeration for the old property name
@@ -800,13 +891,13 @@ HRESULT WINAPI StorageBaseImpl_RenameElement(
 
     /*
      * 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
+     * now, before Destroying the old property we must zero its 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
+     * This means that we need to tweak the StgProperty if it is a stream or a
      * non empty storage.
      */
     StorageImpl_ReadProperty(This->ancestorStorage,
@@ -822,9 +913,9 @@ HRESULT WINAPI StorageBaseImpl_RenameElement(
 
     /*
      * Invoke Destroy to get rid of the ole property and automatically redo
-     * the linking of it's previous and next members...
+     * the linking of its previous and next members...
      */
-    StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
+    IStorage_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
 
   }
   else
@@ -845,7 +936,7 @@ HRESULT WINAPI StorageBaseImpl_RenameElement(
  *
  * See Windows documentation for more details on IStorage methods.
  */
-HRESULT WINAPI StorageBaseImpl_CreateStream(
+static HRESULT WINAPI StorageBaseImpl_CreateStream(
             IStorage*        iface,
             const OLECHAR*   pwcsName,  /* [string][in] */
             DWORD            grfMode,   /* [in] */
@@ -859,7 +950,7 @@ HRESULT WINAPI StorageBaseImpl_CreateStream(
   StgProperty       currentProperty, newStreamProperty;
   ULONG             foundPropertyIndex, newPropertyIndex;
 
-  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
+  TRACE("(%p, %s, %x, %d, %d, %p)\n",
        iface, debugstr_w(pwcsName), grfMode,
        reserved1, reserved2, ppstm);
 
@@ -881,7 +972,7 @@ HRESULT WINAPI StorageBaseImpl_CreateStream(
   if ( FAILED( validateSTGM(grfMode) ))
     return STG_E_INVALIDFLAG;
 
-  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) )
+  if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) 
     return STG_E_INVALIDFLAG;
 
   /*
@@ -891,6 +982,15 @@ HRESULT WINAPI StorageBaseImpl_CreateStream(
       (grfMode & STGM_TRANSACTED))
     return STG_E_INVALIDFUNCTION;
 
+  /*
+   * Check that we're compatible with the parent's storage mode
+   * if not in transacted mode
+   */
+  if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) {
+    if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
+      return STG_E_ACCESSDENIED;
+  }
+
   /*
    * Initialize the out parameter
    */
@@ -913,13 +1013,18 @@ HRESULT WINAPI StorageBaseImpl_CreateStream(
     /*
      * An element with this name already exists
      */
-    if (grfMode & STGM_CREATE)
+    if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
     {
       IStorage_DestroyElement(iface, pwcsName);
     }
     else
       return STG_E_FILEALREADYEXISTS;
   }
+  else if (STGM_ACCESS_MODE(This->openFlags) == STGM_READ)
+  {
+    WARN("read-only storage\n");
+    return STG_E_ACCESSDENIED;
+  }
 
   /*
    * memset the empty property
@@ -986,7 +1091,7 @@ HRESULT WINAPI StorageBaseImpl_CreateStream(
      * Since we are returning a pointer to the interface, we have to nail down
      * the reference.
      */
-    StgStreamImpl_AddRef(*ppstm);
+    IStream_AddRef(*ppstm);
   }
   else
   {
@@ -1004,7 +1109,7 @@ HRESULT WINAPI StorageBaseImpl_CreateStream(
  *
  * See Windows documentation for more details on IStorage methods.
  */
-HRESULT WINAPI StorageBaseImpl_SetClass(
+static HRESULT WINAPI StorageBaseImpl_SetClass(
   IStorage*        iface,
   REFCLSID         clsid) /* [in] */
 {
@@ -1043,7 +1148,7 @@ HRESULT WINAPI StorageBaseImpl_SetClass(
  *
  * See Windows documentation for more details on IStorage methods.
  */
-HRESULT WINAPI StorageImpl_CreateStorage(
+static HRESULT WINAPI StorageImpl_CreateStorage(
   IStorage*      iface,
   const OLECHAR  *pwcsName, /* [string][in] */
   DWORD            grfMode,   /* [in] */
@@ -1060,7 +1165,7 @@ HRESULT WINAPI StorageImpl_CreateStorage(
   ULONG            newPropertyIndex;
   HRESULT          hr;
 
-  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
+  TRACE("(%p, %s, %x, %d, %d, %p)\n",
        iface, debugstr_w(pwcsName), grfMode,
        reserved1, reserved2, ppstg);
 
@@ -1073,23 +1178,35 @@ HRESULT WINAPI StorageImpl_CreateStorage(
   if (pwcsName == 0)
     return STG_E_INVALIDNAME;
 
+  /*
+   * Initialize the out parameter
+   */
+  *ppstg = NULL;
+
   /*
    * Validate the STGM flags
    */
   if ( FAILED( validateSTGM(grfMode) ) ||
        (grfMode & STGM_DELETEONRELEASE) )
+  {
+    WARN("bad grfMode: 0x%x\n", grfMode);
     return STG_E_INVALIDFLAG;
+  }
 
   /*
-   * Initialize the out parameter
+   * Check that we're compatible with the parent's storage mode
    */
-  *ppstg = 0;
+  if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->base.openFlags ) )
+  {
+    WARN("access denied\n");
+    return STG_E_ACCESSDENIED;
+  }
 
   /*
    * Create a property enumeration and search the properties
    */
-  propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
-                                                    This->rootPropertySetIndex);
+  propertyEnumeration = IEnumSTATSTGImpl_Construct( This->base.ancestorStorage,
+                                                    This->base.rootPropertySetIndex);
 
   foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
                                                      pwcsName,
@@ -1101,10 +1218,18 @@ HRESULT WINAPI StorageImpl_CreateStorage(
     /*
      * An element with this name already exists
      */
-    if (grfMode & STGM_CREATE)
+    if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
       IStorage_DestroyElement(iface, pwcsName);
     else
+    {
+      WARN("file already exists\n");
       return STG_E_FILEALREADYEXISTS;
+    }
+  }
+  else if (STGM_ACCESS_MODE(This->base.openFlags) == STGM_READ)
+  {
+    WARN("read-only storage\n");
+    return STG_E_ACCESSDENIED;
   }
 
   /*
@@ -1115,7 +1240,10 @@ HRESULT WINAPI StorageImpl_CreateStorage(
   newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
 
   if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+  {
+    FIXME("name too long\n");
     return STG_E_INVALIDNAME;
+  }
 
   strcpyW(newProperty.name, pwcsName);
 
@@ -1140,13 +1268,13 @@ HRESULT WINAPI StorageImpl_CreateStorage(
   /*
    * Obtain a free property in the property chain
    */
-  newPropertyIndex = getFreeProperty(This->ancestorStorage);
+  newPropertyIndex = getFreeProperty(This->base.ancestorStorage);
 
   /*
    * Save the new property into the new property spot
    */
   StorageImpl_WriteProperty(
-    This->ancestorStorage,
+    This->base.ancestorStorage,
     newPropertyIndex,
     &newProperty);
 
@@ -1199,7 +1327,7 @@ static ULONG getFreeProperty(
     /*
      * Start by reading the root property
      */
-    readSuccessful = StorageImpl_ReadProperty(storage->ancestorStorage,
+    readSuccessful = StorageImpl_ReadProperty(storage->base.ancestorStorage,
                                                currentPropertyIndex,
                                                &currentProperty);
     if (readSuccessful)
@@ -1238,7 +1366,7 @@ static ULONG getFreeProperty(
      * obtain the new count of property blocks
      */
     blockCount = BlockChainStream_GetCount(
-                   storage->ancestorStorage->rootBlockChain)+1;
+                   storage->base.ancestorStorage->rootBlockChain)+1;
 
     /*
      * initialize the size used by the property stream
@@ -1249,7 +1377,7 @@ static ULONG getFreeProperty(
     /*
      * add a property block to the property chain
      */
-    BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
+    BlockChainStream_SetSize(storage->base.ancestorStorage->rootBlockChain, newSize);
 
     /*
      * memset the empty property in order to initialize the unused newly
@@ -1268,7 +1396,7 @@ static ULONG getFreeProperty(
       propertyIndex++)
     {
       StorageImpl_WriteProperty(
-        storage->ancestorStorage,
+        storage->base.ancestorStorage,
         propertyIndex,
         &emptyProperty);
     }
@@ -1321,8 +1449,8 @@ static void updatePropertyChain(
   /*
    * Read the root property
    */
-  StorageImpl_ReadProperty(storage->ancestorStorage,
-                             storage->rootPropertySetIndex,
+  StorageImpl_ReadProperty(storage->base.ancestorStorage,
+                             storage->base.rootPropertySetIndex,
                              &currentProperty);
 
   if (currentProperty.dirProperty != PROPERTY_NULL)
@@ -1342,7 +1470,7 @@ static void updatePropertyChain(
     /*
      * Read
      */
-    StorageImpl_ReadProperty(storage->ancestorStorage,
+    StorageImpl_ReadProperty(storage->base.ancestorStorage,
                                currentProperty.dirProperty,
                                &currentProperty);
 
@@ -1358,7 +1486,7 @@ static void updatePropertyChain(
       {
         if (previous != PROPERTY_NULL)
         {
-          StorageImpl_ReadProperty(storage->ancestorStorage,
+          StorageImpl_ReadProperty(storage->base.ancestorStorage,
                                      previous,
                                      &currentProperty);
           current = previous;
@@ -1366,7 +1494,7 @@ static void updatePropertyChain(
         else
         {
           currentProperty.previousProperty = newPropertyIndex;
-          StorageImpl_WriteProperty(storage->ancestorStorage,
+          StorageImpl_WriteProperty(storage->base.ancestorStorage,
                                       current,
                                       &currentProperty);
           found = 1;
@@ -1376,7 +1504,7 @@ static void updatePropertyChain(
       {
         if (next != PROPERTY_NULL)
         {
-          StorageImpl_ReadProperty(storage->ancestorStorage,
+          StorageImpl_ReadProperty(storage->base.ancestorStorage,
                                      next,
                                      &currentProperty);
           current = next;
@@ -1384,7 +1512,7 @@ static void updatePropertyChain(
         else
         {
           currentProperty.nextProperty = newPropertyIndex;
-          StorageImpl_WriteProperty(storage->ancestorStorage,
+          StorageImpl_WriteProperty(storage->base.ancestorStorage,
                                       current,
                                       &currentProperty);
           found = 1;
@@ -1406,11 +1534,11 @@ static void updatePropertyChain(
   else
   {
     /*
-     * The root storage is empty, link the new property to it's dir property
+     * The root storage is empty, link the new property to its dir property
      */
     currentProperty.dirProperty = newPropertyIndex;
-    StorageImpl_WriteProperty(storage->ancestorStorage,
-                                storage->rootPropertySetIndex,
+    StorageImpl_WriteProperty(storage->base.ancestorStorage,
+                                storage->base.rootPropertySetIndex,
                                 &currentProperty);
   }
 }
@@ -1419,7 +1547,7 @@ static void updatePropertyChain(
 /*************************************************************************
  * CopyTo (IStorage)
  */
-HRESULT WINAPI StorageImpl_CopyTo(
+static HRESULT WINAPI StorageImpl_CopyTo(
   IStorage*   iface,
   DWORD       ciidExclude,  /* [in] */
   const IID*  rgiidExclude, /* [size_is][unique][in] */
@@ -1435,7 +1563,7 @@ HRESULT WINAPI StorageImpl_CopyTo(
   if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
     FIXME("Exclude option not implemented\n");
 
-  TRACE("(%p, %ld, %p, %p, %p)\n",
+  TRACE("(%p, %d, %p, %p, %p)\n",
        iface, ciidExclude, rgiidExclude,
        snbExclude, pstgDest);
 
@@ -1569,7 +1697,7 @@ HRESULT WINAPI StorageImpl_CopyTo(
     }
     else
     {
-      WARN("unknown element type: %ld\n", curElement.type);
+      WARN("unknown element type: %d\n", curElement.type);
     }
 
   } while (hr == S_OK);
@@ -1585,50 +1713,61 @@ HRESULT WINAPI StorageImpl_CopyTo(
 /*************************************************************************
  * MoveElementTo (IStorage)
  */
-HRESULT WINAPI StorageImpl_MoveElementTo(
+static 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");
+  FIXME("(%p %s %p %s %u): stub\n", iface,
+         debugstr_w(pwcsName), pstgDest,
+         debugstr_w(pwcsNewName), grfFlags);
   return E_NOTIMPL;
 }
 
 /*************************************************************************
  * Commit (IStorage)
+ *
+ * Ensures that any changes made to a storage object open in transacted mode
+ * are reflected in the parent storage
+ *
+ * NOTES
+ *  Wine doesn't implement transacted mode, which seems to be a basic
+ *  optimization, so we can ignore this stub for now.
  */
-HRESULT WINAPI StorageImpl_Commit(
+static HRESULT WINAPI StorageImpl_Commit(
   IStorage*   iface,
   DWORD         grfCommitFlags)/* [in] */
 {
-  FIXME("(%ld): stub!\n", grfCommitFlags);
+  FIXME("(%p %d): stub\n", iface, grfCommitFlags);
   return S_OK;
 }
 
 /*************************************************************************
  * Revert (IStorage)
+ *
+ * Discard all changes that have been made since the last commit operation
  */
-HRESULT WINAPI StorageImpl_Revert(
+static HRESULT WINAPI StorageImpl_Revert(
   IStorage* iface)
 {
-  FIXME("not implemented!\n");
+  FIXME("(%p): stub\n", iface);
   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
+ * Strategy: This implementation is built this way for simplicity not for speed.
+ *          I always delete the topmost 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
+ *          storage object.  The optimisation resides in the usage of another
+ *          enumeration strategy that would give all the leaves of a storage
  *          first. (postfix order)
  */
-HRESULT WINAPI StorageImpl_DestroyElement(
+static HRESULT WINAPI StorageImpl_DestroyElement(
   IStorage*     iface,
   const OLECHAR *pwcsName)/* [string][in] */
 {
@@ -1641,7 +1780,7 @@ HRESULT WINAPI StorageImpl_DestroyElement(
   StgProperty       parentProperty;
   ULONG             foundPropertyIndexToDelete;
   ULONG             typeOfRelation;
-  ULONG             parentPropertyId;
+  ULONG             parentPropertyId = 0;
 
   TRACE("(%p, %s)\n",
        iface, debugstr_w(pwcsName));
@@ -1656,8 +1795,8 @@ HRESULT WINAPI StorageImpl_DestroyElement(
    * Create a property enumeration to search the property with the given name
    */
   propertyEnumeration = IEnumSTATSTGImpl_Construct(
-    This->ancestorStorage,
-    This->rootPropertySetIndex);
+    This->base.ancestorStorage,
+    This->base.rootPropertySetIndex);
 
   foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
     propertyEnumeration,
@@ -1674,15 +1813,15 @@ HRESULT WINAPI StorageImpl_DestroyElement(
   /*
    * 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...
+   * the parent is This. Otherwise, the parent is one of its sibling...
    */
 
   /*
    * First, read This's StgProperty..
    */
   res = StorageImpl_ReadProperty(
-          This->ancestorStorage,
-          This->rootPropertySetIndex,
+          This->base.ancestorStorage,
+          This->base.rootPropertySetIndex,
           &parentProperty);
 
   assert(res);
@@ -1697,7 +1836,7 @@ HRESULT WINAPI StorageImpl_DestroyElement(
      * Set data as it would have been done in the else part...
      */
     typeOfRelation   = PROPERTY_RELATION_DIR;
-    parentPropertyId = This->rootPropertySetIndex;
+    parentPropertyId = This->base.rootPropertySetIndex;
   }
   else
   {
@@ -1708,8 +1847,8 @@ HRESULT WINAPI StorageImpl_DestroyElement(
     IEnumSTATSTGImpl* propertyEnumeration2;
 
     propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
-      This->ancestorStorage,
-      This->rootPropertySetIndex);
+      This->base.ancestorStorage,
+      This->base.rootPropertySetIndex);
 
     typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
       propertyEnumeration2,
@@ -1759,7 +1898,7 @@ HRESULT WINAPI StorageImpl_DestroyElement(
  *
  * See Windows documentation for more details on IStorage methods.
  */
-HRESULT WINAPI StorageImpl_Stat( IStorage* iface,
+static HRESULT WINAPI StorageImpl_Stat( IStorage* iface,
                                  STATSTG*  pstatstg,     /* [out] */
                                  DWORD     grfStatFlag)  /* [in] */
 {
@@ -1776,6 +1915,34 @@ HRESULT WINAPI StorageImpl_Stat( IStorage* iface,
   return result;
 }
 
+/******************************************************************************
+ * Internal stream list handlers
+ */
+
+void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm)
+{
+  TRACE("Stream added (stg=%p strm=%p)\n", stg, strm);
+  list_add_tail(&stg->strmHead,&strm->StrmListEntry);
+}
+
+void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm)
+{
+  TRACE("Stream removed (stg=%p strm=%p)\n", stg,strm);
+  list_remove(&(strm->StrmListEntry));
+}
+
+static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg)
+{
+  struct list *cur, *cur2;
+  StgStreamImpl *strm=NULL;
+
+  LIST_FOR_EACH_SAFE(cur, cur2, &stg->strmHead) {
+    strm = LIST_ENTRY(cur,StgStreamImpl,StrmListEntry);
+    TRACE("Streams deleted (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev);
+    strm->parentStorage = NULL;
+    list_remove(cur);
+  }
+}
 
 
 /*********************************************************************
@@ -1803,7 +1970,7 @@ static HRESULT deleteStorageProperty(
         (IStorage*)parentStorage,
         propertyToDelete.name,
         0,
-        STGM_SHARE_EXCLUSIVE,
+        STGM_WRITE | STGM_SHARE_EXCLUSIVE,
         0,
         0,
         &childStorage);
@@ -1842,11 +2009,11 @@ static HRESULT deleteStorageProperty(
   } while ((hr == S_OK) && (destroyHr == S_OK));
 
   /*
-   * Invalidate the property by zeroing it's name member.
+   * Invalidate the property by zeroing its name member.
    */
   propertyToDelete.sizeOfNameString = 0;
 
-  StorageImpl_WriteProperty(parentStorage->ancestorStorage,
+  StorageImpl_WriteProperty(parentStorage->base.ancestorStorage,
                             indexOfPropertyToDelete,
                             &propertyToDelete);
 
@@ -1904,7 +2071,7 @@ static HRESULT deleteStreamProperty(
   IStream_Release(pis);
 
   /*
-   * Invalidate the property by zeroing it's name member.
+   * Invalidate the property by zeroing its name member.
    */
   propertyToDelete.sizeOfNameString = 0;
 
@@ -1913,7 +2080,7 @@ static HRESULT deleteStreamProperty(
    * but since we are here to zap it, I don't do it...
    */
   StorageImpl_WriteProperty(
-    parentStorage->ancestorStorage,
+    parentStorage->base.ancestorStorage,
     indexOfPropertyToDelete,
     &propertyToDelete);
 
@@ -1941,7 +2108,7 @@ static HRESULT findPlaceholder(
    * Read the storage property
    */
   res = StorageImpl_ReadProperty(
-          storage->ancestorStorage,
+          storage->base.ancestorStorage,
           storePropertyIndex,
           &storeProperty);
 
@@ -1997,7 +2164,7 @@ static HRESULT findPlaceholder(
   }
 
   hr = StorageImpl_WriteProperty(
-         storage->ancestorStorage,
+         storage->base.ancestorStorage,
          storePropertyIndex,
          &storeProperty);
 
@@ -2139,7 +2306,7 @@ static HRESULT adjustPropertyChain(
    * Write back the parent property
    */
   res = StorageImpl_WriteProperty(
-          This->ancestorStorage,
+          This->base.ancestorStorage,
           parentPropertyId,
           &parentProperty);
   if(! res)
@@ -2167,7 +2334,7 @@ static HRESULT adjustPropertyChain(
 /******************************************************************************
  * SetElementTimes (IStorage)
  */
-HRESULT WINAPI StorageImpl_SetElementTimes(
+static HRESULT WINAPI StorageImpl_SetElementTimes(
   IStorage*     iface,
   const OLECHAR *pwcsName,/* [string][in] */
   const FILETIME  *pctime,  /* [in] */
@@ -2181,16 +2348,42 @@ HRESULT WINAPI StorageImpl_SetElementTimes(
 /******************************************************************************
  * SetStateBits (IStorage)
  */
-HRESULT WINAPI StorageImpl_SetStateBits(
+static HRESULT WINAPI StorageImpl_SetStateBits(
   IStorage*   iface,
   DWORD         grfStateBits,/* [in] */
   DWORD         grfMask)     /* [in] */
 {
-  FIXME("not implemented!\n");
-  return E_NOTIMPL;
+  StorageImpl* const This = (StorageImpl*)iface;
+  This->base.stateBits = (This->base.stateBits & ~grfMask) | (grfStateBits & grfMask);
+  return S_OK;
 }
 
-HRESULT StorageImpl_Construct(
+/*
+ * Virtual function table for the IStorage32Impl class.
+ */
+static const 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
+};
+
+static HRESULT StorageImpl_Construct(
   StorageImpl* This,
   HANDLE       hFile,
   LPCOLESTR    pwcsName,
@@ -2209,17 +2402,25 @@ HRESULT StorageImpl_Construct(
 
   memset(This, 0, sizeof(StorageImpl));
 
+  /*
+   * Initialize stream list
+   */
+
+  list_init(&This->base.strmHead);
+
   /*
    * Initialize the virtual function table.
    */
-  This->lpVtbl = &Storage32Impl_Vtbl;
-  This->v_destructor = &StorageImpl_Destroy;
+  This->base.lpVtbl = &Storage32Impl_Vtbl;
+  This->base.pssVtbl = &IPropertySetStorage_Vtbl;
+  This->base.v_destructor = &StorageImpl_Destroy;
+  This->base.openFlags = (openFlags & ~STGM_CREATE);
 
   /*
    * This is the top-level storage so initialize the ancestor pointer
    * to this.
    */
-  This->ancestorStorage = This;
+  This->base.ancestorStorage = This;
 
   /*
    * Initialize the physical support of the storage.
@@ -2254,7 +2455,7 @@ HRESULT StorageImpl_Construct(
   if (fileCreate)
   {
     ULARGE_INTEGER size;
-    BYTE* bigBlockBuffer;
+    BYTE bigBlockBuffer[BIG_BLOCK_SIZE];
 
     /*
      * Initialize all header variables:
@@ -2287,11 +2488,10 @@ HRESULT StorageImpl_Construct(
     /*
      * 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);
+    StorageImpl_WriteBigBlock(This, 0, bigBlockBuffer);
   }
   else
   {
@@ -2331,7 +2531,7 @@ HRESULT StorageImpl_Construct(
     return STG_E_READFAULT;
 
   /*
-   * Write the root property
+   * Write the root property (memory only)
    */
   if (fileCreate)
   {
@@ -2371,13 +2571,13 @@ HRESULT StorageImpl_Construct(
       if ( (currentProperty.sizeOfNameString != 0 ) &&
            (currentProperty.propertyType     == PROPTYPE_ROOT) )
       {
-        This->rootPropertySetIndex = currentPropertyIndex;
+        This->base.rootPropertySetIndex = currentPropertyIndex;
       }
     }
 
     currentPropertyIndex++;
 
-  } while (readSuccessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
+  } while (readSuccessful && (This->base.rootPropertySetIndex == PROPERTY_NULL) );
 
   if (!readSuccessful)
   {
@@ -2389,17 +2589,19 @@ HRESULT StorageImpl_Construct(
    * Create the block chain abstraction for the small block root chain.
    */
   if(!(This->smallBlockRootChain =
-       BlockChainStream_Construct(This, NULL, This->rootPropertySetIndex)))
+       BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex)))
     return STG_E_READFAULT;
 
   return hr;
 }
 
-void StorageImpl_Destroy(
-  StorageImpl* This)
+static void StorageImpl_Destroy(StorageBaseImpl* iface)
 {
+  StorageImpl *This = (StorageImpl*) iface;
   TRACE("(%p)\n", This);
 
+  StorageBaseImpl_DeleteAll(&This->base);
+
   HeapFree(GetProcessHeap(), 0, This->pwcsName);
 
   BlockChainStream_Destroy(This->smallBlockRootChain);
@@ -2407,7 +2609,7 @@ void StorageImpl_Destroy(
   BlockChainStream_Destroy(This->smallBlockDepotChain);
 
   BIGBLOCKFILE_Destructor(This->bigBlockFile);
-  return;
+  HeapFree(GetProcessHeap(), 0, This);
 }
 
 /******************************************************************************
@@ -2417,11 +2619,12 @@ void StorageImpl_Destroy(
  * If the big block depot is filled, this method will enlarge it.
  *
  */
-ULONG StorageImpl_GetNextFreeBigBlock(
+static ULONG StorageImpl_GetNextFreeBigBlock(
   StorageImpl* This)
 {
   ULONG depotBlockIndexPos;
-  void  *depotBuffer;
+  BYTE depotBuffer[BIG_BLOCK_SIZE];
+  BOOL success;
   ULONG depotBlockOffset;
   ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
   ULONG nextBlockIndex    = BLOCK_SPECIAL;
@@ -2514,9 +2717,9 @@ ULONG StorageImpl_GetNextFreeBigBlock(
       }
     }
 
-    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+    success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
 
-    if (depotBuffer != 0)
+    if (success)
     {
       while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
               ( nextBlockIndex != BLOCK_UNUSED))
@@ -2531,14 +2734,17 @@ ULONG StorageImpl_GetNextFreeBigBlock(
 
         depotBlockOffset += sizeof(ULONG);
       }
-
-      StorageImpl_ReleaseBigBlock(This, depotBuffer);
     }
 
     depotIndex++;
     depotBlockOffset = 0;
   }
 
+  /*
+   * make sure that the block physically exists before using it
+   */
+  BIGBLOCKFILE_EnsureExists(This->bigBlockFile, freeBlock);
+
   This->prevFreeBlock = freeBlock;
 
   return freeBlock;
@@ -2550,18 +2756,15 @@ ULONG StorageImpl_GetNextFreeBigBlock(
  * This will create a depot block, essentially it is a block initialized
  * to BLOCK_UNUSEDs.
  */
-void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
+static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
 {
-  BYTE* blockBuffer;
-
-  blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
+  BYTE blockBuffer[BIG_BLOCK_SIZE];
 
   /*
    * Initialize blocks as free
    */
   memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
-
-  StorageImpl_ReleaseBigBlock(This, blockBuffer);
+  StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
 }
 
 /******************************************************************************
@@ -2571,7 +2774,7 @@ void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
  * index. This method is only for depot indexes equal or greater than
  * COUNT_BBDEPOTINHEADER.
  */
-ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
+static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
 {
   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
@@ -2592,20 +2795,8 @@ ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
   }
 
   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);
-    }
-  }
+    StorageImpl_ReadDWordFromBigBlock(This, extBlockIndex,
+                        extBlockOffset * sizeof(ULONG), &blockIndex);
 
   return blockIndex;
 }
@@ -2617,9 +2808,7 @@ ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
  * This method is only for depot indexes equal or greater than
  * COUNT_BBDEPOTINHEADER.
  */
-void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
-                                    ULONG depotIndex,
-                                    ULONG blockIndex)
+static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex)
 {
   ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
   ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
@@ -2637,18 +2826,9 @@ void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
 
   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);
-    }
+    StorageImpl_WriteDWordToBigBlock(This, extBlockIndex,
+                        extBlockOffset * sizeof(ULONG),
+                        blockIndex);
   }
 }
 
@@ -2657,11 +2837,11 @@ void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
  *
  * Creates an extended depot block.
  */
-ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
+static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
 {
   ULONG numExtBlocks           = This->extBigBlockDepotCount;
   ULONG nextExtBlock           = This->extBigBlockDepotStart;
-  BYTE* depotBuffer            = NULL;
+  BYTE  depotBuffer[BIG_BLOCK_SIZE];
   ULONG index                  = BLOCK_UNUSED;
   ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
   ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
@@ -2691,17 +2871,15 @@ ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
     /*
      * Add the new extended block to the chain.
      */
-    depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
-    StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
-    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset,
+                                     index);
   }
 
   /*
    * Initialize this block.
    */
-  depotBuffer = StorageImpl_GetBigBlock(This, index);
   memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
-  StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  StorageImpl_WriteBigBlock(This, index, depotBuffer);
 
   return index;
 }
@@ -2711,7 +2889,7 @@ ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
  *
  * This method will flag the specified block as free in the big block depot.
  */
-void  StorageImpl_FreeBigBlock(
+static void StorageImpl_FreeBigBlock(
   StorageImpl* This,
   ULONG          blockIndex)
 {
@@ -2745,7 +2923,7 @@ void  StorageImpl_FreeBigBlock(
  *
  * See Windows documentation for more details on IStorage methods.
  */
-HRESULT StorageImpl_GetNextBlockInChain(
+static HRESULT StorageImpl_GetNextBlockInChain(
   StorageImpl* This,
   ULONG        blockIndex,
   ULONG*       nextBlockIndex)
@@ -2753,7 +2931,8 @@ HRESULT StorageImpl_GetNextBlockInChain(
   ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
-  void* depotBuffer;
+  BYTE depotBuffer[BIG_BLOCK_SIZE];
+  BOOL success;
   ULONG depotBlockIndexPos;
   int index;
 
@@ -2761,7 +2940,7 @@ HRESULT StorageImpl_GetNextBlockInChain(
 
   if(depotBlockCount >= This->bigBlockDepotCount)
   {
-    WARN("depotBlockCount %ld, bigBlockDepotCount %ld\n", depotBlockCount,
+    WARN("depotBlockCount %d, bigBlockDepotCount %d\n", depotBlockCount,
         This->bigBlockDepotCount);
     return STG_E_READFAULT;
   }
@@ -2785,9 +2964,9 @@ HRESULT StorageImpl_GetNextBlockInChain(
       depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
     }
 
-    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+    success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
 
-    if (!depotBuffer)
+    if (!success)
       return STG_E_READFAULT;
 
     for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
@@ -2795,7 +2974,6 @@ HRESULT StorageImpl_GetNextBlockInChain(
       StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
       This->blockDepotCached[index] = *nextBlockIndex;
     }
-    StorageImpl_ReleaseBigBlock(This, depotBuffer);
   }
 
   *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
@@ -2818,20 +2996,13 @@ HRESULT StorageImpl_GetNextBlockInChain(
  *    - BLOCK_UNUSED: there is no next extended block.
  *    - Any other return values denotes failure.
  */
-ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
+static 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);
-  }
+  StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset,
+                        &nextBlockIndex);
 
   return nextBlockIndex;
 }
@@ -2850,7 +3021,7 @@ ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
  * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
  *
  */
-void  StorageImpl_SetNextBlockInChain(
+static void StorageImpl_SetNextBlockInChain(
           StorageImpl* This,
           ULONG          blockIndex,
           ULONG          nextBlock)
@@ -2859,7 +3030,6 @@ void  StorageImpl_SetNextBlockInChain(
   ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
   ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
   ULONG depotBlockIndexPos;
-  void* depotBuffer;
 
   assert(depotBlockCount < This->bigBlockDepotCount);
   assert(blockIndex != nextBlock);
@@ -2876,14 +3046,8 @@ void  StorageImpl_SetNextBlockInChain(
     depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
   }
 
-  depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
-
-  if (depotBuffer!=0)
-  {
-    StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
-    StorageImpl_ReleaseBigBlock(This, depotBuffer);
-  }
-
+  StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset,
+                        nextBlock);
   /*
    * Update the cached block depot, if necessary.
    */
@@ -2898,22 +3062,24 @@ void  StorageImpl_SetNextBlockInChain(
  *
  * This method will read in the file header, i.e. big block index -1.
  */
-HRESULT StorageImpl_LoadFileHeader(
+static HRESULT StorageImpl_LoadFileHeader(
           StorageImpl* This)
 {
   HRESULT hr = STG_E_FILENOTFOUND;
-  void*   headerBigBlock = NULL;
+  BYTE    headerBigBlock[BIG_BLOCK_SIZE];
+  BOOL    success;
   int     index;
 
+  TRACE("\n");
   /*
    * Get a pointer to the big block of data containing the header.
    */
-  headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
+  success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
 
   /*
    * Extract the information from the header.
    */
-  if (headerBigBlock!=0)
+  if (success)
   {
     /*
      * Check for the "magic number" signature and return an error if it is not
@@ -2921,13 +3087,11 @@ HRESULT StorageImpl_LoadFileHeader(
      */
     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;
     }
 
@@ -3000,11 +3164,6 @@ HRESULT StorageImpl_LoadFileHeader(
     }
     else
        hr = S_OK;
-
-    /*
-     * Release the block.
-     */
-    StorageImpl_ReleaseBigBlock(This, headerBigBlock);
   }
 
   return hr;
@@ -3015,7 +3174,7 @@ HRESULT StorageImpl_LoadFileHeader(
  *
  * This method will save to the file the header, i.e. big block -1.
  */
-void StorageImpl_SaveFileHeader(
+static void StorageImpl_SaveFileHeader(
           StorageImpl* This)
 {
   BYTE   headerBigBlock[BIG_BLOCK_SIZE];
@@ -3121,23 +3280,23 @@ BOOL StorageImpl_ReadProperty(
 {
   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
   ULARGE_INTEGER offsetInPropSet;
-  BOOL         readSuccessful;
+  HRESULT        readRes;
   ULONG          bytesRead;
 
   offsetInPropSet.u.HighPart = 0;
   offsetInPropSet.u.LowPart  = index * PROPSET_BLOCK_SIZE;
 
-  readSuccessful = BlockChainStream_ReadAt(
+  readRes = BlockChainStream_ReadAt(
                     This->rootBlockChain,
                     offsetInPropSet,
                     PROPSET_BLOCK_SIZE,
                     currentProperty,
                     &bytesRead);
 
-  if (readSuccessful)
+  if (SUCCEEDED(readRes))
   {
     /* replace the name of root entry (often "Root Entry") by the file name */
-    WCHAR *propName = (index == This->rootPropertySetIndex) ?
+    WCHAR *propName = (index == This->base.rootPropertySetIndex) ?
                        This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME;
 
     memset(buffer->name, 0, sizeof(buffer->name));
@@ -3207,7 +3366,7 @@ BOOL StorageImpl_ReadProperty(
     buffer->size.u.HighPart = 0;
   }
 
-  return readSuccessful;
+  return SUCCEEDED(readRes) ? TRUE : FALSE;
 }
 
 /*********************************************************************
@@ -3220,7 +3379,7 @@ BOOL StorageImpl_WriteProperty(
 {
   BYTE           currentProperty[PROPSET_BLOCK_SIZE];
   ULARGE_INTEGER offsetInPropSet;
-  BOOL         writeSuccessful;
+  HRESULT        writeRes;
   ULONG          bytesWritten;
 
   offsetInPropSet.u.HighPart = 0;
@@ -3290,75 +3449,79 @@ BOOL StorageImpl_WriteProperty(
       OFFSET_PS_SIZE,
       buffer->size.u.LowPart);
 
-  writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain,
-                                            offsetInPropSet,
-                                            PROPSET_BLOCK_SIZE,
-                                            currentProperty,
-                                            &bytesWritten);
-  return writeSuccessful;
+  writeRes = BlockChainStream_WriteAt(This->rootBlockChain,
+                                      offsetInPropSet,
+                                      PROPSET_BLOCK_SIZE,
+                                      currentProperty,
+                                      &bytesWritten);
+  return SUCCEEDED(writeRes) ? TRUE : FALSE;
 }
 
-BOOL StorageImpl_ReadBigBlock(
+static BOOL StorageImpl_ReadBigBlock(
   StorageImpl* This,
   ULONG          blockIndex,
   void*          buffer)
 {
-  void* bigBlockBuffer;
+  ULARGE_INTEGER ulOffset;
+  DWORD  read;
 
-  bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
+  ulOffset.u.HighPart = 0;
+  ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
 
-  if (bigBlockBuffer!=0)
-  {
-    memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
+  StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
+  return (read == This->bigBlockSize);
+}
 
-    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+static BOOL StorageImpl_ReadDWordFromBigBlock(
+  StorageImpl*  This,
+  ULONG         blockIndex,
+  ULONG         offset,
+  DWORD*        value)
+{
+  ULARGE_INTEGER ulOffset;
+  DWORD  read;
+  DWORD  tmp;
 
-    return TRUE;
-  }
+  ulOffset.u.HighPart = 0;
+  ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
+  ulOffset.u.LowPart += offset;
 
-  return FALSE;
+  StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
+  *value = le32toh(tmp);
+  return (read == sizeof(DWORD));
 }
 
-BOOL StorageImpl_WriteBigBlock(
+static BOOL StorageImpl_WriteBigBlock(
   StorageImpl* This,
   ULONG          blockIndex,
   void*          buffer)
 {
-  void* bigBlockBuffer;
-
-  bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
-
-  if (bigBlockBuffer!=0)
-  {
-    memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
+  ULARGE_INTEGER ulOffset;
+  DWORD  wrote;
 
-    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+  ulOffset.u.HighPart = 0;
+  ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
 
-    return TRUE;
-  }
-
-  return FALSE;
+  StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
+  return (wrote == This->bigBlockSize);
 }
 
-void* StorageImpl_GetROBigBlock(
+static BOOL StorageImpl_WriteDWordToBigBlock(
   StorageImpl* This,
-  ULONG          blockIndex)
+  ULONG         blockIndex,
+  ULONG         offset,
+  DWORD         value)
 {
-  return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
-}
+  ULARGE_INTEGER ulOffset;
+  DWORD  wrote;
 
-void* StorageImpl_GetBigBlock(
-  StorageImpl* This,
-  ULONG          blockIndex)
-{
-  return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
-}
+  ulOffset.u.HighPart = 0;
+  ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
+  ulOffset.u.LowPart += offset;
 
-void StorageImpl_ReleaseBigBlock(
-  StorageImpl* This,
-  void*          pBigBlock)
-{
-  BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
+  value = htole32(value);
+  StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
+  return (wrote == sizeof(DWORD));
 }
 
 /******************************************************************************
@@ -3373,9 +3536,11 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
 {
   ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
   ULARGE_INTEGER size, offset;
-  ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
+  ULONG cbRead, cbWritten;
+  ULARGE_INTEGER cbTotalRead;
   ULONG propertyIndex;
-  BOOL successRead, successWrite;
+  HRESULT resWrite = S_OK;
+  HRESULT resRead;
   StgProperty chainProperty;
   BYTE *buffer;
   BlockChainStream *bbTempChain = NULL;
@@ -3402,32 +3567,43 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
    */
   offset.u.LowPart = 0;
   offset.u.HighPart = 0;
-  cbTotalRead = 0;
-  cbTotalWritten = 0;
+  cbTotalRead.QuadPart = 0;
 
-  buffer = (BYTE *) HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
+  buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
   do
   {
-    successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
-                                               offset,
-                                               DEF_SMALL_BLOCK_SIZE,
-                                               buffer,
-                                               &cbRead);
-    cbTotalRead += cbRead;
+    resRead = SmallBlockChainStream_ReadAt(*ppsbChain,
+                                           offset,
+                                           This->smallBlockSize,
+                                           buffer,
+                                           &cbRead);
+    if (FAILED(resRead))
+        break;
 
-    successWrite = BlockChainStream_WriteAt(bbTempChain,
+    if (cbRead > 0)
+    {
+        cbTotalRead.QuadPart += cbRead;
+
+        resWrite = BlockChainStream_WriteAt(bbTempChain,
                                             offset,
                                             cbRead,
                                             buffer,
                                             &cbWritten);
-    cbTotalWritten += cbWritten;
 
-    offset.u.LowPart += This->smallBlockSize;
+        if (FAILED(resWrite))
+            break;
 
-  } while (successRead && successWrite);
+        offset.u.LowPart += This->smallBlockSize;
+    }
+  } while (cbTotalRead.QuadPart < size.QuadPart);
   HeapFree(GetProcessHeap(),0,buffer);
 
-  assert(cbTotalRead == cbTotalWritten);
+  if (FAILED(resRead) || FAILED(resWrite))
+  {
+    ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
+    BlockChainStream_Destroy(bbTempChain);
+    return NULL;
+  }
 
   /*
    * Destroy the small block chain.
@@ -3461,52 +3637,11 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
   return bigBlockChain;
 }
 
-/******************************************************************************
-** Storage32InternalImpl implementation
-*/
-
-StorageInternalImpl* StorageInternalImpl_Construct(
-  StorageImpl* ancestorStorage,
-  ULONG          rootPropertyIndex)
+static void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
 {
-  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->lpVtbl = &Storage32InternalImpl_Vtbl;
-    newStorage->v_destructor = &StorageInternalImpl_Destroy;
-
-    /*
-     * Keep the ancestor storage pointer and nail a reference to it.
-     */
-    newStorage->ancestorStorage = ancestorStorage;
-    StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
-
-    /*
-     * Keep the index of the root property set for this storage,
-     */
-    newStorage->rootPropertySetIndex = rootPropertyIndex;
+  StorageInternalImpl* This = (StorageInternalImpl*) iface;
 
-    return newStorage;
-  }
-
-  return 0;
-}
-
-void StorageInternalImpl_Destroy(
-  StorageInternalImpl* This)
-{
-  StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
+  StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage);
   HeapFree(GetProcessHeap(), 0, This);
 }
 
@@ -3517,7 +3652,7 @@ void StorageInternalImpl_Destroy(
 ** The non-root storages cannot be opened in transacted mode thus this function
 ** does nothing.
 */
-HRESULT WINAPI StorageInternalImpl_Commit(
+static HRESULT WINAPI StorageInternalImpl_Commit(
   IStorage*            iface,
   DWORD                  grfCommitFlags)  /* [in] */
 {
@@ -3531,66 +3666,20 @@ HRESULT WINAPI StorageInternalImpl_Commit(
 ** The non-root storages cannot be opened in transacted mode thus this function
 ** does nothing.
 */
-HRESULT WINAPI StorageInternalImpl_Revert(
+static HRESULT WINAPI StorageInternalImpl_Revert(
   IStorage*            iface)
 {
   return S_OK;
 }
 
-/******************************************************************************
-** 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;
-}
-
-void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
+static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
 {
   IStorage_Release((IStorage*)This->parentStorage);
   HeapFree(GetProcessHeap(), 0, This->stackToVisit);
   HeapFree(GetProcessHeap(), 0, This);
 }
 
-HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
+static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
   IEnumSTATSTG*     iface,
   REFIID            riid,
   void**            ppvObject)
@@ -3611,38 +3700,25 @@ HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
   /*
    * Compare the riid with the interface IDs implemented by this object.
    */
-  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
-  {
-    *ppvObject = (IEnumSTATSTG*)This;
-  }
-  else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
+  if (IsEqualGUID(&IID_IUnknown, riid) ||
+      IsEqualGUID(&IID_IEnumSTATSTG, riid))
   {
     *ppvObject = (IEnumSTATSTG*)This;
+    IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
+    return S_OK;
   }
 
-  /*
-   * 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
-   */
-  IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
-
-  return S_OK;
+  return E_NOINTERFACE;
 }
 
-ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
+static ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
   IEnumSTATSTG* iface)
 {
   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
   return InterlockedIncrement(&This->ref);
 }
 
-ULONG   WINAPI IEnumSTATSTGImpl_Release(
+static ULONG   WINAPI IEnumSTATSTGImpl_Release(
   IEnumSTATSTG* iface)
 {
   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
@@ -3662,7 +3738,7 @@ ULONG   WINAPI IEnumSTATSTGImpl_Release(
   return newRef;
 }
 
-HRESULT WINAPI IEnumSTATSTGImpl_Next(
+static HRESULT WINAPI IEnumSTATSTGImpl_Next(
   IEnumSTATSTG* iface,
   ULONG             celt,
   STATSTG*          rgelt,
@@ -3745,7 +3821,7 @@ HRESULT WINAPI IEnumSTATSTGImpl_Next(
 }
 
 
-HRESULT WINAPI IEnumSTATSTGImpl_Skip(
+static HRESULT WINAPI IEnumSTATSTGImpl_Skip(
   IEnumSTATSTG* iface,
   ULONG             celt)
 {
@@ -3797,7 +3873,7 @@ HRESULT WINAPI IEnumSTATSTGImpl_Skip(
   return S_FALSE;
 }
 
-HRESULT WINAPI IEnumSTATSTGImpl_Reset(
+static HRESULT WINAPI IEnumSTATSTGImpl_Reset(
   IEnumSTATSTG* iface)
 {
   IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
@@ -3831,7 +3907,7 @@ HRESULT WINAPI IEnumSTATSTGImpl_Reset(
   return S_OK;
 }
 
-HRESULT WINAPI IEnumSTATSTGImpl_Clone(
+static HRESULT WINAPI IEnumSTATSTGImpl_Clone(
   IEnumSTATSTG* iface,
   IEnumSTATSTG**    ppenum)
 {
@@ -3874,7 +3950,7 @@ HRESULT WINAPI IEnumSTATSTGImpl_Clone(
   return S_OK;
 }
 
-INT IEnumSTATSTGImpl_FindParentProperty(
+static INT IEnumSTATSTGImpl_FindParentProperty(
   IEnumSTATSTGImpl *This,
   ULONG             childProperty,
   StgProperty      *currentProperty,
@@ -3939,7 +4015,7 @@ INT IEnumSTATSTGImpl_FindParentProperty(
   return PROPERTY_NULL;
 }
 
-ULONG IEnumSTATSTGImpl_FindProperty(
+static ULONG IEnumSTATSTGImpl_FindProperty(
   IEnumSTATSTGImpl* This,
   const OLECHAR*  lpszPropName,
   StgProperty*      currentProperty)
@@ -3984,7 +4060,7 @@ ULONG IEnumSTATSTGImpl_FindProperty(
   return PROPERTY_NULL;
 }
 
-void IEnumSTATSTGImpl_PushSearchNode(
+static void IEnumSTATSTGImpl_PushSearchNode(
   IEnumSTATSTGImpl* This,
   ULONG             nodeToPush)
 {
@@ -4033,7 +4109,7 @@ void IEnumSTATSTGImpl_PushSearchNode(
   }
 }
 
-ULONG IEnumSTATSTGImpl_PopSearchNode(
+static ULONG IEnumSTATSTGImpl_PopSearchNode(
   IEnumSTATSTGImpl* This,
   BOOL            remove)
 {
@@ -4050,46 +4126,214 @@ ULONG IEnumSTATSTGImpl_PopSearchNode(
   return topNode;
 }
 
+/*
+ * Virtual function table for the IEnumSTATSTGImpl class.
+ */
+static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
+{
+    IEnumSTATSTGImpl_QueryInterface,
+    IEnumSTATSTGImpl_AddRef,
+    IEnumSTATSTGImpl_Release,
+    IEnumSTATSTGImpl_Next,
+    IEnumSTATSTGImpl_Skip,
+    IEnumSTATSTGImpl_Reset,
+    IEnumSTATSTGImpl_Clone
+};
+
+/******************************************************************************
+** IEnumSTATSTGImpl implementation
+*/
+
+static 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 const 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
+*/
+
+static StorageInternalImpl* StorageInternalImpl_Construct(
+  StorageImpl* ancestorStorage,
+  DWORD        openFlags,
+  ULONG        rootPropertyIndex)
+{
+  StorageInternalImpl* newStorage;
+
+  /*
+   * Allocate space for the new storage object
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StorageInternalImpl));
+
+  if (newStorage!=0)
+  {
+    /*
+     * Initialize the stream list
+     */
+    list_init(&newStorage->base.strmHead);
+
+    /*
+     * Initialize the virtual function table.
+     */
+    newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;
+    newStorage->base.v_destructor = &StorageInternalImpl_Destroy;
+    newStorage->base.openFlags = (openFlags & ~STGM_CREATE);
+
+    /*
+     * 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(void* buffer, ULONG offset, WORD* value)
+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)
 {
-  memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
+  value = htole16(value);
+  memcpy(buffer+offset, &value, sizeof(WORD));
 }
 
-void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
+void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)
 {
-  memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
+  DWORD tmp;
+
+  memcpy(&tmp, buffer+offset, sizeof(DWORD));
+  *value = le32toh(tmp);
 }
 
-void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
+void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)
 {
-  memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
+  value = htole32(value);
+  memcpy(buffer+offset, &value, sizeof(DWORD));
 }
 
-void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
+void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
+ ULARGE_INTEGER* value)
 {
-  memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
+#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_ReadGUID(void* buffer, ULONG offset, GUID* value)
+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, (BYTE*)buffer+offset+8, sizeof(value->Data4));
+  memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
 }
 
-void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
+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((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
+  memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));
 }
 
 void StorageUtl_CopyPropertyToSTATSTG(
@@ -4195,7 +4439,7 @@ void BlockChainStream_Destroy(BlockChainStream* This)
  * This->headOfStreamPlaceHolder.
  *
  */
-ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
+static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
 {
   StgProperty chainProperty;
   BOOL      readSuccessful;
@@ -4226,7 +4470,7 @@ ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
  * This is not the size of the stream as the last block may not be full!
  *
  */
-ULONG BlockChainStream_GetCount(BlockChainStream* This)
+static ULONG BlockChainStream_GetCount(BlockChainStream* This)
 {
   ULONG blockIndex;
   ULONG count = 0;
@@ -4254,7 +4498,7 @@ ULONG BlockChainStream_GetCount(BlockChainStream* This)
  * bytesRead may be NULL.
  * Failure will be returned if the specified number of bytes has not been read.
  */
-BOOL BlockChainStream_ReadAt(BlockChainStream* This,
+HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
   ULARGE_INTEGER offset,
   ULONG          size,
   void*          buffer,
@@ -4265,7 +4509,8 @@ BOOL BlockChainStream_ReadAt(BlockChainStream* This,
   ULONG bytesToReadInBuffer;
   ULONG blockIndex;
   BYTE* bufferWalker;
-  BYTE* bigBlockBuffer;
+
+  TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
 
   /*
    * Find the first block in the stream that contains part of the buffer.
@@ -4289,10 +4534,13 @@ BOOL BlockChainStream_ReadAt(BlockChainStream* This,
   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
   {
     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
-      return FALSE;
+      return STG_E_DOCFILECORRUPT;
     blockNoInSequence--;
   }
 
+  if ((blockNoInSequence > 0) && (blockIndex == BLOCK_END_OF_CHAIN))
+      return STG_E_DOCFILECORRUPT; /* We failed to find the starting block */
+
   This->lastBlockNoInSequenceIndex = blockIndex;
 
   /*
@@ -4303,36 +4551,40 @@ BOOL BlockChainStream_ReadAt(BlockChainStream* This,
 
   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
   {
+    ULARGE_INTEGER ulOffset;
+    DWORD bytesReadAt;
     /*
      * 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);
+     TRACE("block %i\n",blockIndex);
+     ulOffset.u.HighPart = 0;
+     ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) +
+                             offsetInBlock;
 
+     StorageImpl_ReadAt(This->parentStorage,
+         ulOffset,
+         bufferWalker,
+         bytesToReadInBuffer,
+         &bytesReadAt);
     /*
      * Step to the next big block.
      */
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
-      return FALSE;
+    if( size > bytesReadAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
+      return STG_E_DOCFILECORRUPT;
 
-    bufferWalker += bytesToReadInBuffer;
-    size         -= bytesToReadInBuffer;
-    *bytesRead   += bytesToReadInBuffer;
+    bufferWalker += bytesReadAt;
+    size         -= bytesReadAt;
+    *bytesRead   += bytesReadAt;
     offsetInBlock = 0;  /* There is no offset on the next block */
 
+    if (bytesToReadInBuffer != bytesReadAt)
+        break;
   }
 
-  return (size == 0);
+  return (size == 0) ? S_OK : STG_E_READFAULT;
 }
 
 /******************************************************************************
@@ -4342,7 +4594,7 @@ BOOL BlockChainStream_ReadAt(BlockChainStream* This,
  * bytesWritten may be NULL.
  * Will fail if not all specified number of bytes have been written.
  */
-BOOL BlockChainStream_WriteAt(BlockChainStream* This,
+HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
   ULARGE_INTEGER    offset,
   ULONG             size,
   const void*       buffer,
@@ -4353,7 +4605,6 @@ BOOL BlockChainStream_WriteAt(BlockChainStream* This,
   ULONG bytesToWrite;
   ULONG blockIndex;
   const BYTE* bufferWalker;
-  BYTE* bigBlockBuffer;
 
   /*
    * Find the first block in the stream that contains part of the buffer.
@@ -4378,12 +4629,20 @@ BOOL BlockChainStream_WriteAt(BlockChainStream* This,
   {
     if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
                                              &blockIndex)))
-      return FALSE;
+      return STG_E_DOCFILECORRUPT;
     blockNoInSequence--;
   }
 
   This->lastBlockNoInSequenceIndex = blockIndex;
 
+  /* BlockChainStream_SetSize should have already been called to ensure we have
+   * enough blocks in the chain to write into */
+  if (blockIndex == BLOCK_END_OF_CHAIN)
+  {
+    ERR("not enough blocks in chain to write data\n");
+    return STG_E_DOCFILECORRUPT;
+  }
+
   /*
    * Here, I'm casting away the constness on the buffer variable
    * This is OK since we don't intend to modify that buffer.
@@ -4393,34 +4652,42 @@ BOOL BlockChainStream_WriteAt(BlockChainStream* This,
 
   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
   {
+    ULARGE_INTEGER ulOffset;
+    DWORD bytesWrittenAt;
     /*
      * 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);
+    TRACE("block %i\n",blockIndex);
+    ulOffset.u.HighPart = 0;
+    ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) +
+                             offsetInBlock;
 
-    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+    StorageImpl_WriteAt(This->parentStorage,
+         ulOffset,
+         (BYTE*)bufferWalker,
+         bytesToWrite,
+         &bytesWrittenAt);
 
     /*
      * Step to the next big block.
      */
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
+    if(size > bytesWrittenAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
                                              &blockIndex)))
-      return FALSE;
-    bufferWalker  += bytesToWrite;
-    size          -= bytesToWrite;
-    *bytesWritten += bytesToWrite;
+      return STG_E_DOCFILECORRUPT;
+
+    bufferWalker  += bytesWrittenAt;
+    size          -= bytesWrittenAt;
+    *bytesWritten += bytesWrittenAt;
     offsetInBlock  = 0;      /* There is no offset on the next block */
+
+    if (bytesWrittenAt != bytesToWrite)
+      break;
   }
 
-  return (size == 0);
+  return (size == 0) ? S_OK : STG_E_WRITEFAULT;
 }
 
 /******************************************************************************
@@ -4428,8 +4695,8 @@ BOOL BlockChainStream_WriteAt(BlockChainStream* This,
  *
  * Shrinks this chain in the big block depot.
  */
-BOOL BlockChainStream_Shrink(BlockChainStream* This,
-                               ULARGE_INTEGER    newSize)
+static BOOL BlockChainStream_Shrink(BlockChainStream* This,
+                                    ULARGE_INTEGER    newSize)
 {
   ULONG blockIndex, extraBlock;
   ULONG numBlocks;
@@ -4496,8 +4763,8 @@ BOOL BlockChainStream_Shrink(BlockChainStream* This,
  *
  * Grows this chain in the big block depot.
  */
-BOOL BlockChainStream_Enlarge(BlockChainStream* This,
-                                ULARGE_INTEGER    newSize)
+static BOOL BlockChainStream_Enlarge(BlockChainStream* This,
+                                     ULARGE_INTEGER    newSize)
 {
   ULONG blockIndex, currentBlock;
   ULONG newNumBlocks;
@@ -4627,21 +4894,6 @@ BOOL BlockChainStream_SetSize(
   }
   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);
   }
 
@@ -4654,7 +4906,7 @@ BOOL BlockChainStream_SetSize(
  * 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)
+static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
 {
   StgProperty chainProperty;
 
@@ -4718,7 +4970,7 @@ void SmallBlockChainStream_Destroy(
  *
  * Returns the head of this chain of small blocks.
  */
-ULONG SmallBlockChainStream_GetHeadOfChain(
+static ULONG SmallBlockChainStream_GetHeadOfChain(
   SmallBlockChainStream* This)
 {
   StgProperty chainProperty;
@@ -4750,7 +5002,7 @@ ULONG SmallBlockChainStream_GetHeadOfChain(
  *    - BLOCK_END_OF_CHAIN: end of this chain
  *    - BLOCK_UNUSED: small block 'blockIndex' is free
  */
-HRESULT SmallBlockChainStream_GetNextBlockInChain(
+static HRESULT SmallBlockChainStream_GetNextBlockInChain(
   SmallBlockChainStream* This,
   ULONG                  blockIndex,
   ULONG*                 nextBlockInChain)
@@ -4758,7 +5010,7 @@ HRESULT SmallBlockChainStream_GetNextBlockInChain(
   ULARGE_INTEGER offsetOfBlockInDepot;
   DWORD  buffer;
   ULONG  bytesRead;
-  BOOL success;
+  HRESULT res;
 
   *nextBlockInChain = BLOCK_END_OF_CHAIN;
 
@@ -4768,20 +5020,20 @@ HRESULT SmallBlockChainStream_GetNextBlockInChain(
   /*
    * Read those bytes in the buffer from the small block file.
    */
-  success = BlockChainStream_ReadAt(
+  res = BlockChainStream_ReadAt(
               This->parentStorage->smallBlockDepotChain,
               offsetOfBlockInDepot,
               sizeof(DWORD),
               &buffer,
               &bytesRead);
 
-  if (success)
+  if (SUCCEEDED(res))
   {
-    StorageUtl_ReadDWord(&buffer, 0, nextBlockInChain);
+    StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
     return S_OK;
   }
 
-  return STG_E_READFAULT;
+  return res;
 }
 
 /******************************************************************************
@@ -4792,7 +5044,7 @@ HRESULT SmallBlockChainStream_GetNextBlockInChain(
  * 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(
+static void SmallBlockChainStream_SetNextBlockInChain(
   SmallBlockChainStream* This,
   ULONG                  blockIndex,
   ULONG                  nextBlock)
@@ -4804,7 +5056,7 @@ void SmallBlockChainStream_SetNextBlockInChain(
   offsetOfBlockInDepot.u.HighPart = 0;
   offsetOfBlockInDepot.u.LowPart  = blockIndex * sizeof(ULONG);
 
-  StorageUtl_WriteDWord(&buffer, 0, nextBlock);
+  StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
 
   /*
    * Read those bytes in the buffer from the small block file.
@@ -4822,7 +5074,7 @@ void SmallBlockChainStream_SetNextBlockInChain(
  *
  * Flag small block 'blockIndex' as free in the small block depot.
  */
-void SmallBlockChainStream_FreeBlock(
+static void SmallBlockChainStream_FreeBlock(
   SmallBlockChainStream* This,
   ULONG                  blockIndex)
 {
@@ -4836,7 +5088,7 @@ void SmallBlockChainStream_FreeBlock(
  * enlarged if necessary. The small block chain will also be enlarged if
  * necessary.
  */
-ULONG SmallBlockChainStream_GetNextFreeBlock(
+static ULONG SmallBlockChainStream_GetNextFreeBlock(
   SmallBlockChainStream* This)
 {
   ULARGE_INTEGER offsetOfBlockInDepot;
@@ -4844,7 +5096,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock(
   ULONG bytesRead;
   ULONG blockIndex = 0;
   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
-  BOOL success = TRUE;
+  HRESULT res = S_OK;
   ULONG smallBlocksPerBigBlock;
 
   offsetOfBlockInDepot.u.HighPart = 0;
@@ -4856,7 +5108,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock(
   {
     offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
 
-    success = BlockChainStream_ReadAt(
+    res = BlockChainStream_ReadAt(
                 This->parentStorage->smallBlockDepotChain,
                 offsetOfBlockInDepot,
                 sizeof(DWORD),
@@ -4866,9 +5118,9 @@ ULONG SmallBlockChainStream_GetNextFreeBlock(
     /*
      * If we run out of space for the small block depot, enlarge it
      */
-    if (success)
+    if (SUCCEEDED(res))
     {
-      StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
+      StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
 
       if (nextBlockIndex != BLOCK_UNUSED)
         blockIndex++;
@@ -4880,7 +5132,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock(
 
       ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
       ULONG nextBlock, newsbdIndex;
-      BYTE* smallBlockDepot;
+      BYTE smallBlockDepot[BIG_BLOCK_SIZE];
 
       nextBlock = sbdIndex;
       while (nextBlock != BLOCK_END_OF_CHAIN)
@@ -4904,11 +5156,8 @@ ULONG SmallBlockChainStream_GetNextFreeBlock(
       /*
        * 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);
+      StorageImpl_WriteBigBlock(This->parentStorage, newsbdIndex, smallBlockDepot);
 
       if (count == 0)
       {
@@ -4937,7 +5186,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock(
 
         StorageImpl_ReadProperty(
           This->parentStorage,
-          This->parentStorage->rootPropertySetIndex,
+          This->parentStorage->base.rootPropertySetIndex,
           &rootProp);
 
         rootProp.startingBlock = sbStartIndex;
@@ -4946,7 +5195,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock(
 
         StorageImpl_WriteProperty(
           This->parentStorage,
-          This->parentStorage->rootPropertySetIndex,
+          This->parentStorage->base.rootPropertySetIndex,
           &rootProp);
       }
     }
@@ -4965,7 +5214,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock(
 
     StorageImpl_ReadProperty(
       This->parentStorage,
-      This->parentStorage->rootPropertySetIndex,
+      This->parentStorage->base.rootPropertySetIndex,
       &rootProp);
 
     if (rootProp.size.u.LowPart <
@@ -4979,7 +5228,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock(
 
       StorageImpl_WriteProperty(
         This->parentStorage,
-        This->parentStorage->rootPropertySetIndex,
+        This->parentStorage->base.rootPropertySetIndex,
         &rootProp);
     }
   }
@@ -4994,13 +5243,14 @@ ULONG SmallBlockChainStream_GetNextFreeBlock(
  * bytesRead may be NULL.
  * Failure will be returned if the specified number of bytes has not been read.
  */
-BOOL SmallBlockChainStream_ReadAt(
+HRESULT SmallBlockChainStream_ReadAt(
   SmallBlockChainStream* This,
   ULARGE_INTEGER         offset,
   ULONG                  size,
   void*                  buffer,
   ULONG*                 bytesRead)
 {
+  HRESULT rc = S_OK;
   ULARGE_INTEGER offsetInBigBlockFile;
   ULONG blockNoInSequence =
     offset.u.LowPart / This->parentStorage->smallBlockSize;
@@ -5023,9 +5273,9 @@ BOOL SmallBlockChainStream_ReadAt(
 
   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
   {
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
-                                                       &blockIndex)))
-      return FALSE;
+    rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
+    if(FAILED(rc))
+      return rc;
     blockNoInSequence--;
   }
 
@@ -5054,27 +5304,32 @@ BOOL SmallBlockChainStream_ReadAt(
 
     /*
      * Read those bytes in the buffer from the small block file.
+     * The small block has already been identified so it shouldn't fail
+     * unless the file is corrupt.
      */
-    BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
+    rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
       offsetInBigBlockFile,
       bytesToReadInBuffer,
       bufferWalker,
       &bytesReadFromBigBlockFile);
 
-    assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
+    if (FAILED(rc))
+      return rc;
 
     /*
      * 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 */
+    rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
+    if(FAILED(rc))
+      return STG_E_DOCFILECORRUPT;
+
+    bufferWalker += bytesReadFromBigBlockFile;
+    size         -= bytesReadFromBigBlockFile;
+    *bytesRead   += bytesReadFromBigBlockFile;
+    offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
   }
 
-  return (size == 0);
+  return (size == 0) ? S_OK : STG_E_READFAULT;
 }
 
 /******************************************************************************
@@ -5084,7 +5339,7 @@ BOOL SmallBlockChainStream_ReadAt(
  * bytesWritten may be NULL.
  * Will fail if not all specified number of bytes have been written.
  */
-BOOL SmallBlockChainStream_WriteAt(
+HRESULT SmallBlockChainStream_WriteAt(
   SmallBlockChainStream* This,
   ULARGE_INTEGER offset,
   ULONG          size,
@@ -5098,8 +5353,9 @@ BOOL SmallBlockChainStream_WriteAt(
   ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
   ULONG bytesToWriteInBuffer;
   ULONG blockIndex;
-  ULONG bytesWrittenFromBigBlockFile;
+  ULONG bytesWrittenToBigBlockFile;
   const BYTE* bufferWalker;
+  HRESULT res;
 
   /*
    * This should never happen on a small block file.
@@ -5114,7 +5370,7 @@ BOOL SmallBlockChainStream_WriteAt(
   while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
   {
     if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
-      return FALSE;
+      return STG_E_DOCFILECORRUPT;
     blockNoInSequence--;
   }
 
@@ -5146,13 +5402,14 @@ BOOL SmallBlockChainStream_WriteAt(
     /*
      * Write those bytes in the buffer to the small block file.
      */
-    BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
+    res = BlockChainStream_WriteAt(
+      This->parentStorage->smallBlockRootChain,
       offsetInBigBlockFile,
       bytesToWriteInBuffer,
       bufferWalker,
-      &bytesWrittenFromBigBlockFile);
-
-    assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
+      &bytesWrittenToBigBlockFile);
+    if (FAILED(res))
+      return res;
 
     /*
      * Step to the next big block.
@@ -5160,13 +5417,13 @@ BOOL SmallBlockChainStream_WriteAt(
     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 */
+    bufferWalker  += bytesWrittenToBigBlockFile;
+    size          -= bytesWrittenToBigBlockFile;
+    *bytesWritten += bytesWrittenToBigBlockFile;
+    offsetInBlock  = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize;
   }
 
-  return (size == 0);
+  return (size == 0) ? S_OK : STG_E_WRITEFAULT;
 }
 
 /******************************************************************************
@@ -5174,7 +5431,7 @@ BOOL SmallBlockChainStream_WriteAt(
  *
  * Shrinks this chain in the small block depot.
  */
-BOOL SmallBlockChainStream_Shrink(
+static BOOL SmallBlockChainStream_Shrink(
   SmallBlockChainStream* This,
   ULARGE_INTEGER newSize)
 {
@@ -5257,7 +5514,7 @@ BOOL SmallBlockChainStream_Shrink(
  *
  * Grows this chain in the small block depot.
  */
-BOOL SmallBlockChainStream_Enlarge(
+static BOOL SmallBlockChainStream_Enlarge(
   SmallBlockChainStream* This,
   ULARGE_INTEGER newSize)
 {
@@ -5322,37 +5579,13 @@ BOOL SmallBlockChainStream_Enlarge(
     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++;
+      BLOCK_END_OF_CHAIN);
 
-    if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
-      return 0;
+    currentBlock = blockIndex;
+    oldNumBlocks++;
   }
 
-  return count;
+  return TRUE;
 }
 
 /******************************************************************************
@@ -5391,7 +5624,7 @@ BOOL SmallBlockChainStream_SetSize(
  *
  * Returns the size of this chain.
  */
-ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
+static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
 {
   StgProperty chainProperty;
 
@@ -5405,6 +5638,22 @@ ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
 
 /******************************************************************************
  *    StgCreateDocfile  [OLE32.@]
+ * Creates a new compound file storage object
+ *
+ * PARAMS
+ *  pwcsName  [ I] Unicode string with filename (can be relative or NULL)
+ *  grfMode   [ I] Access mode for opening the new storage object (see STGM_ constants)
+ *  reserved  [ ?] unused?, usually 0
+ *  ppstgOpen [IO] A pointer to IStorage pointer to the new onject
+ *
+ * RETURNS
+ *  S_OK if the file was successfully created
+ *  some STG_E_ value if error
+ * NOTES
+ *  if pwcsName is NULL, create file with new unique name
+ *  the function can returns
+ *  STG_S_CONVERTED if the specified file was successfully converted to storage format
+ *  (unrealized now)
  */
 HRESULT WINAPI StgCreateDocfile(
   LPCOLESTR pwcsName,
@@ -5414,14 +5663,14 @@ HRESULT WINAPI StgCreateDocfile(
 {
   StorageImpl* newStorage = 0;
   HANDLE       hFile      = INVALID_HANDLE_VALUE;
-  HRESULT        hr         = S_OK;
+  HRESULT        hr         = STG_E_INVALIDFLAG;
   DWORD          shareMode;
   DWORD          accessMode;
   DWORD          creationMode;
   DWORD          fileAttributes;
   WCHAR          tempFileName[MAX_PATH];
 
-  TRACE("(%s, %lx, %ld, %p)\n",
+  TRACE("(%s, %x, %d, %p)\n",
        debugstr_w(pwcsName), grfMode,
        reserved, ppstgOpen);
 
@@ -5433,20 +5682,32 @@ HRESULT WINAPI StgCreateDocfile(
   if (reserved != 0)
     return STG_E_INVALIDPARAMETER;
 
+  /* if no share mode given then DENY_NONE is the default */
+  if (STGM_SHARE_MODE(grfMode) == 0)
+      grfMode |= STGM_SHARE_DENY_NONE;
+
   /*
    * Validate the STGM flags
    */
   if ( FAILED( validateSTGM(grfMode) ))
-    return STG_E_INVALIDFLAG;
+    goto end;
 
-  /* StgCreateDocFile always opens for write */
-  if (!(grfMode & (STGM_WRITE|STGM_READWRITE)))
-    return STG_E_INVALIDFLAG;
+  /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
+  switch(STGM_ACCESS_MODE(grfMode))
+  {
+  case STGM_WRITE:
+  case STGM_READWRITE:
+    break;
+  default:
+    goto end;
+  }
+
+  /* in direct mode, can only use SHARE_EXCLUSIVE */
+  if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
+    goto end;
+
+  /* but in transacted mode, any share mode is valid */
 
-  /* always opens non-shared */
-  if (!(grfMode & STGM_SHARE_EXCLUSIVE))
-    return STG_E_INVALIDFLAG;
-      
   /*
    * Generate a unique name.
    */
@@ -5455,11 +5716,6 @@ HRESULT WINAPI StgCreateDocfile(
     WCHAR tempPath[MAX_PATH];
     static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
 
-    if (!(grfMode & STGM_SHARE_EXCLUSIVE))
-      return STG_E_INVALIDFLAG;
-    if (!(grfMode & (STGM_WRITE|STGM_READWRITE)))
-      return STG_E_INVALIDFLAG;
-
     memset(tempPath, 0, sizeof(tempPath));
     memset(tempFileName, 0, sizeof(tempFileName));
 
@@ -5469,7 +5725,10 @@ HRESULT WINAPI StgCreateDocfile(
     if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
       pwcsName = tempFileName;
     else
-      return STG_E_INSUFFICIENTMEMORY;
+    {
+      hr = STG_E_INSUFFICIENTMEMORY;
+      goto end;
+    }
 
     creationMode = TRUNCATE_EXISTING;
   }
@@ -5500,16 +5759,18 @@ HRESULT WINAPI StgCreateDocfile(
   hFile = CreateFileW(pwcsName,
                         accessMode,
                         shareMode,
-            NULL,
+                        NULL,
                         creationMode,
                         fileAttributes,
-            0);
+                        0);
 
   if (hFile == INVALID_HANDLE_VALUE)
   {
     if(GetLastError() == ERROR_FILE_EXISTS)
-      return STG_E_FILEALREADYEXISTS;
-    return E_FAIL;
+      hr = STG_E_FILEALREADYEXISTS;
+    else
+      hr = E_FAIL;
+    goto end;
   }
 
   /*
@@ -5518,7 +5779,10 @@ HRESULT WINAPI StgCreateDocfile(
   newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
 
   if (newStorage == 0)
-    return STG_E_INSUFFICIENTMEMORY;
+  {
+    hr = STG_E_INSUFFICIENTMEMORY;
+    goto end;
+  }
 
   hr = StorageImpl_Construct(
          newStorage,
@@ -5532,7 +5796,7 @@ HRESULT WINAPI StgCreateDocfile(
   if (FAILED(hr))
   {
     HeapFree(GetProcessHeap(), 0, newStorage);
-    return hr;
+    goto end;
   }
 
   /*
@@ -5542,6 +5806,8 @@ HRESULT WINAPI StgCreateDocfile(
          (IStorage*)newStorage,
          (REFIID)&IID_IStorage,
          (void**)ppstgOpen);
+end:
+  TRACE("<-- %p  r = %08x\n", *ppstgOpen, hr);
 
   return hr;
 }
@@ -5551,47 +5817,188 @@ HRESULT WINAPI StgCreateDocfile(
  */
 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),
+    TRACE("(%s, %x, %x, %x, %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%x, %p)\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, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
           grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
-    return STG_E_UNIMPLEMENTEDFUNCTION;
+
+    if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
+    {
+        ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
+        return STG_E_INVALIDPARAMETER;  
+    }
+
+    switch (stgfmt)
+    {
+    case STGFMT_FILE:
+        ERR("Cannot use STGFMT_FILE - this is NTFS only\n");  
+        return STG_E_INVALIDPARAMETER;
+        
+    case STGFMT_STORAGE:
+        break;
+
+    case STGFMT_DOCFILE:
+        if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
+        {
+            ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
+            return STG_E_INVALIDPARAMETER;  
+        }
+        FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
+        break;
+
+    case STGFMT_ANY:
+        WARN("STGFMT_ANY assuming storage\n");
+        break;
+
+    default:
+        return STG_E_INVALIDPARAMETER;
+    }
+
+    return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); 
 }
 
+
 /******************************************************************************
  *              StgOpenStorage        [OLE32.@]
  */
 HRESULT WINAPI StgOpenStorage(
   const OLECHAR *pwcsName,
   IStorage      *pstgPriority,
-  DWORD           grfMode,
-  SNB           snbExclude,
-  DWORD           reserved,
-  IStorage      **ppstgOpen)
+  DWORD          grfMode,
+  SNB            snbExclude,
+  DWORD          reserved,
+  IStorage     **ppstgOpen)
 {
-  StorageImpl* newStorage = 0;
+  StorageImpl*   newStorage = 0;
   HRESULT        hr = S_OK;
-  HANDLE       hFile = 0;
+  HANDLE         hFile = 0;
   DWORD          shareMode;
   DWORD          accessMode;
   WCHAR          fullname[MAX_PATH];
-  DWORD          length;
 
-  TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
+  TRACE("(%s, %p, %x, %p, %d, %p)\n",
        debugstr_w(pwcsName), pstgPriority, grfMode,
        snbExclude, reserved, ppstgOpen);
 
   /*
-   * Perform a sanity check
+   * Perform sanity checks
    */
-  if (( pwcsName == 0) || (ppstgOpen == 0) )
+  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;
+  }
+
+  if (grfMode & STGM_PRIORITY)
+  {
+    if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
+      return STG_E_INVALIDFLAG;
+    if (grfMode & STGM_DELETEONRELEASE)
+      return STG_E_INVALIDFUNCTION;
+    if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
+      return STG_E_INVALIDFLAG;
+    grfMode &= ~0xf0; /* remove the existing sharing mode */
+    grfMode |= STGM_SHARE_DENY_NONE;
+
+    /* STGM_PRIORITY stops other IStorage objects on the same file from
+     * committing until the STGM_PRIORITY IStorage is closed. it also
+     * stops non-transacted mode StgOpenStorage calls with write access from
+     * succeeding. obviously, both of these cannot be achieved through just
+     * file share flags */
+    FIXME("STGM_PRIORITY mode not implemented correctly\n");
+  }
+
+  /*
+   * Validate the sharing mode
+   */
+  if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
+    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) ))
+  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;
@@ -5616,8 +6023,6 @@ HRESULT WINAPI StgOpenStorage(
                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
                        0);
 
-  length = GetFileSize(hFile, NULL);
-
   if (hFile==INVALID_HANDLE_VALUE)
   {
     DWORD last_error = GetLastError();
@@ -5650,6 +6055,17 @@ HRESULT WINAPI StgOpenStorage(
     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
+   */
+  if (GetFileSize(hFile, NULL) < 0x100)
+  {
+    CloseHandle(hFile);
+    hr = STG_E_FILEALREADYEXISTS;
+    goto end;
+  }
+
   /*
    * Allocate and initialize the new IStorage32object.
    */
@@ -5661,15 +6077,15 @@ HRESULT WINAPI StgOpenStorage(
     goto end;
   }
 
-  /* if the file's length was zero, initialize the storage */
+  /* Initialize the storage */
   hr = StorageImpl_Construct(
          newStorage,
          hFile,
-        pwcsName,
+         pwcsName,
          NULL,
          grfMode,
          TRUE,
-        !length );
+         FALSE );
 
   if (FAILED(hr))
   {
@@ -5696,7 +6112,7 @@ HRESULT WINAPI StgOpenStorage(
          (void**)ppstgOpen);
 
 end:
-  TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
+  TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
   return hr;
 }
 
@@ -5823,11 +6239,23 @@ HRESULT WINAPI StgOpenStorageOnILockBytes(
  *
  *
  */
-HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *a,
-                           FILETIME const *b, FILETIME const *c )
+HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
+                           FILETIME const *patime, FILETIME const *pmtime)
 {
-  FIXME("(%s, %p, %p, %p),stub!\n", debugstr_w(str), a, b, c);
-  return S_OK;
+  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;
 }
 
 /******************************************************************************
@@ -5860,7 +6288,8 @@ HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
 {
   HRESULT hRes;
 
-  assert(pStg != 0);
+  if(!pStg)
+    return E_INVALIDARG;
 
   hRes = IStorage_SetClass(pStg, rclsid);
 
@@ -5870,17 +6299,27 @@ HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
 /***********************************************************************
  *    ReadClassStg (OLE32.@)
  *
- * This method reads the CLSID previously written to a storage object with the WriteClassStg.
+ * This method reads the CLSID previously written to a storage object with
+ * the WriteClassStg.
+ *
+ * PARAMS
+ *  pstg    [I] IStorage pointer
+ *  pclsid  [O] Pointer to where the CLSID is written
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: HRESULT code.
  */
 HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
 
     STATSTG pstatstg;
     HRESULT hRes;
 
-    TRACE("()\n");
+    TRACE("(%p, %p)\n", pstg, pclsid);
+
+    if(!pstg || !pclsid)
+        return E_INVALIDARG;
 
-    if(pclsid==NULL)
-        return E_POINTER;
    /*
     * read a STATSTG structure (contains the clsid) from the storage
     */
@@ -5958,6 +6397,9 @@ HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
 /****************************************************************************
  * 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
@@ -5983,79 +6425,74 @@ HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
  */
 static HRESULT validateSTGM(DWORD stgm)
 {
-  BOOL bSTGM_TRANSACTED       = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
-  BOOL bSTGM_SIMPLE           = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
-  BOOL bSTGM_DIRECT           = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
-
-  BOOL bSTGM_WRITE            = ((stgm & STGM_WRITE) == STGM_WRITE);
-  BOOL bSTGM_READWRITE        = ((stgm & STGM_READWRITE) == STGM_READWRITE);
-  BOOL bSTGM_READ             = ! (bSTGM_WRITE || bSTGM_READWRITE);
-
-  BOOL bSTGM_SHARE_DENY_NONE  =
-                     ((stgm & STGM_SHARE_DENY_NONE)  == STGM_SHARE_DENY_NONE);
+  DWORD access = STGM_ACCESS_MODE(stgm);
+  DWORD share  = STGM_SHARE_MODE(stgm);
+  DWORD create = STGM_CREATE_MODE(stgm);
 
-  BOOL bSTGM_SHARE_DENY_READ  =
-                     ((stgm & STGM_SHARE_DENY_READ)  == STGM_SHARE_DENY_READ);
-
-  BOOL bSTGM_SHARE_DENY_WRITE =
-                     ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
+  if (stgm&~STGM_KNOWN_FLAGS)
+  {
+    ERR("unknown flags %08x\n", stgm);
+    return E_FAIL;
+  }
 
-  BOOL bSTGM_SHARE_EXCLUSIVE  =
-                     ((stgm & STGM_SHARE_EXCLUSIVE)  == STGM_SHARE_EXCLUSIVE);
+  switch (access)
+  {
+  case STGM_READ:
+  case STGM_WRITE:
+  case STGM_READWRITE:
+    break;
+  default:
+    return E_FAIL;
+  }
 
-  BOOL bSTGM_CREATE           = ((stgm & STGM_CREATE) == STGM_CREATE);
-  BOOL bSTGM_CONVERT          = ((stgm & STGM_CONVERT) == STGM_CONVERT);
+  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;
+  }
 
-  BOOL bSTGM_NOSCRATCH        = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
-  BOOL bSTGM_NOSNAPSHOT       = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
+  switch (create)
+  {
+  case STGM_CREATE:
+  case STGM_FAILIFTHERE:
+    break;
+  default:
+    return E_FAIL;
+  }
 
   /*
    * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
    */
-  if ( ! bSTGM_DIRECT )
-    if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
-      return E_FAIL;
-
-  /*
-   * STGM_WRITE |  STGM_READWRITE | STGM_READ
-   */
-  if ( ! bSTGM_READ )
-    if( bSTGM_WRITE && bSTGM_READWRITE )
-      return E_FAIL;
-
-  /*
-   * STGM_SHARE_DENY_NONE | others
-   * (I assume here that DENY_READ implies DENY_WRITE)
-   */
-  if ( bSTGM_SHARE_DENY_NONE )
-    if ( bSTGM_SHARE_DENY_READ ||
-         bSTGM_SHARE_DENY_WRITE ||
-         bSTGM_SHARE_EXCLUSIVE)
+  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 ( bSTGM_CREATE && bSTGM_CONVERT )
+  if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
     return E_FAIL;
 
   /*
    * STGM_NOSCRATCH requires STGM_TRANSACTED
    */
-  if ( bSTGM_NOSCRATCH && ! bSTGM_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 (bSTGM_NOSNAPSHOT)
-  {
-    if ( ! ( bSTGM_TRANSACTED &&
-           !(bSTGM_SHARE_EXCLUSIVE || bSTGM_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;
 }
@@ -6068,29 +6505,20 @@ static HRESULT validateSTGM(DWORD stgm)
  */
 static DWORD GetShareModeFromSTGM(DWORD stgm)
 {
-  DWORD dwShareMode = 0;
-  BOOL bSTGM_SHARE_DENY_NONE  =
-                     ((stgm & STGM_SHARE_DENY_NONE)  == STGM_SHARE_DENY_NONE);
-
-  BOOL bSTGM_SHARE_DENY_READ  =
-                     ((stgm & STGM_SHARE_DENY_READ)  == STGM_SHARE_DENY_READ);
-
-  BOOL bSTGM_SHARE_DENY_WRITE =
-                     ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
-
-  BOOL bSTGM_SHARE_EXCLUSIVE  =
-                     ((stgm & STGM_SHARE_EXCLUSIVE)  == STGM_SHARE_EXCLUSIVE);
-
-  if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
-    dwShareMode = 0;
-
-  if (bSTGM_SHARE_DENY_NONE)
-    dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
-
-  if (bSTGM_SHARE_DENY_WRITE)
-    dwShareMode = FILE_SHARE_READ;
-
-  return dwShareMode;
+  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;
 }
 
 /****************************************************************************
@@ -6101,21 +6529,17 @@ static DWORD GetShareModeFromSTGM(DWORD stgm)
  */
 static DWORD GetAccessModeFromSTGM(DWORD stgm)
 {
-  DWORD dwDesiredAccess = GENERIC_READ;
-  BOOL bSTGM_WRITE     = ((stgm & STGM_WRITE) == STGM_WRITE);
-  BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
-  BOOL bSTGM_READ      = ! (bSTGM_WRITE || bSTGM_READWRITE);
-
-  if (bSTGM_READ)
-    dwDesiredAccess = GENERIC_READ;
-
-  if (bSTGM_WRITE)
-    dwDesiredAccess |= GENERIC_WRITE;
-
-  if (bSTGM_READWRITE)
-    dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
-
-  return dwDesiredAccess;
+  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;
 }
 
 /****************************************************************************
@@ -6126,16 +6550,19 @@ static DWORD GetAccessModeFromSTGM(DWORD stgm)
  */
 static DWORD GetCreationModeFromSTGM(DWORD stgm)
 {
-  if ( stgm & STGM_CREATE)
+  switch(STGM_CREATE_MODE(stgm))
+  {
+  case STGM_CREATE:
     return CREATE_ALWAYS;
-  if (stgm & STGM_CONVERT) {
+  case STGM_CONVERT:
     FIXME("STGM_CONVERT not implemented!\n");
     return CREATE_NEW;
+  case STGM_FAILIFTHERE:
+    return CREATE_NEW;
   }
-  /* All other cases */
-  if (stgm & ~ (STGM_CREATE|STGM_CONVERT))
-       FIXME("unhandled storage mode : 0x%08lx\n",stgm & ~ (STGM_CREATE|STGM_CONVERT));
-  return CREATE_NEW;
+  ERR("Invalid create mode!\n");
+  assert(0);
+  return 0;
 }
 
 
@@ -6158,7 +6585,7 @@ static DWORD GetCreationModeFromSTGM(DWORD stgm)
  *
  *     Memory allocated for pData must be freed by the caller
  */
-HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
+static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
 {
        DWORD dwSize;
        HRESULT hRes = S_OK;
@@ -6230,7 +6657,7 @@ HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *
                        {
                                        if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
                                                pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
-                                       pData->pstrOleObjFileName = (CHAR *)HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
+                                       pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
                                        if(pData->pstrOleObjFileName)
                                        {
                                                dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
@@ -6287,7 +6714,7 @@ HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *
                        {
                                if(pData->dwDataLength > 0)
                                {
-                                       pData->pData = (BYTE *)HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
+                                       pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
 
                                        /* Get Data (ex. IStorage, Metafile, or BMP) */
                                        if(pData->pData)
@@ -6326,7 +6753,7 @@ HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *
  *     This function is used by OleConvertIStorageToOLESTREAM only.
  *
  */
-HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
+static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
 {
     DWORD dwSize;
     HRESULT hRes = S_OK;
@@ -6437,7 +6864,7 @@ HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleS
  *
  *
  */
-void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
+static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
 {
     HRESULT hRes;
     HANDLE hFile;
@@ -6487,7 +6914,7 @@ void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD n
  *     Used by OleConvertIStorageToOLESTREAM only.
  *
  */
-DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
+static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
 {
     HANDLE hFile;
     HRESULT hRes;
@@ -6514,7 +6941,7 @@ DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
         if(hFile != INVALID_HANDLE_VALUE)
         {
             nDataLength = GetFileSize(hFile, NULL);
-            *pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,nDataLength);
+            *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
             ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
             CloseHandle(hFile);
         }
@@ -6602,7 +7029,7 @@ static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string )
     if( count != sizeof(len) )
         return E_OUTOFMEMORY;
 
-    TRACE("%ld bytes\n",len);
+    TRACE("%d bytes\n",len);
     
     str = CoTaskMemAlloc( len );
     if( !str )
@@ -6675,61 +7102,6 @@ static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid,
     return r;
 }
 
-/* enumerate HKEY_CLASSES_ROOT\\CLSID looking for a CLSID whose name matches */
-static HRESULT CLSIDFromUserType(LPCWSTR lpszUserType, CLSID *clsid)
-{
-    LONG r, i, len;
-    ULONG count;
-    WCHAR szKey[0x40];
-    HKEY hkey, hkeyclsid;
-    LPWSTR buffer = NULL;
-    BOOL found = FALSE;
-    static const WCHAR szclsid[] = { 'C','L','S','I','D',0 };
-
-    TRACE("Finding CLSID for %s\n", debugstr_w(lpszUserType));
-
-    r = RegOpenKeyW( HKEY_CLASSES_ROOT, szclsid, &hkeyclsid );
-    if( r )
-        return E_INVALIDARG;
-
-    len = lstrlenW( lpszUserType ) + 1;
-    buffer = CoTaskMemAlloc( len * sizeof (WCHAR) );
-    if( !buffer )
-        goto end;
-
-    for(i=0; !found; i++ )
-    {
-        r = RegEnumKeyW( hkeyclsid, i, szKey, sizeof(szKey)/sizeof(WCHAR));
-        if( r != ERROR_SUCCESS )
-            break;
-        hkey = 0;
-        r = RegOpenKeyW( hkeyclsid, szKey, &hkey );
-        if( r != ERROR_SUCCESS )
-            break;
-        count = len * sizeof (WCHAR);
-        r = RegQueryValueW( hkey, NULL, buffer, &count );
-        found = ( r == ERROR_SUCCESS ) &&
-                ( count == len*sizeof(WCHAR) ) && 
-                !lstrcmpW( buffer, lpszUserType ) ;
-        RegCloseKey( hkey );
-    }
-
-end:
-    if( buffer )
-        CoTaskMemFree( buffer );
-    RegCloseKey( hkeyclsid );
-
-    if ( !found )
-        return E_INVALIDARG;
-
-    TRACE("clsid is %s\n", debugstr_w( szKey ) );
-
-    r = CLSIDFromString( szKey, clsid );
-
-    return r;
-}
-
-
 /***********************************************************************
  *               WriteFmtUserTypeStg (OLE32.@)
  */
@@ -6738,47 +7110,32 @@ HRESULT WINAPI WriteFmtUserTypeStg(
 {
     HRESULT r;
     WCHAR szwClipName[0x40];
-    WCHAR szCLSIDName[OLESTREAM_MAX_STR_LEN];
-    CLSID clsid;
-    LPWSTR wstrProgID;
+    CLSID clsid = CLSID_NULL;
+    LPWSTR wstrProgID = NULL;
     DWORD n;
-    LPMALLOC allocator = NULL;
 
     TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
 
-    r = CoGetMalloc(0, &allocator);
-    if( FAILED( r) )
-        return E_OUTOFMEMORY;
-
     /* get the clipboard format name */
     n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) );
     szwClipName[n]=0;
 
     TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
 
-    /* Get the CLSID */
-    szCLSIDName[0]=0;
-    r = CLSIDFromUserType(lpszUserType, &clsid);
-    if( FAILED( r ) )
-        return r;
-
-    TRACE("CLSID is %s\n",debugstr_guid(&clsid));
+    /* 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 */
-    r = ProgIDFromCLSID( &clsid, &wstrProgID);
-    if( FAILED( r ) )
-        return r;
+    /* get the real program ID.  This may fail, but that's fine */
+    ProgIDFromCLSID(&clsid, &wstrProgID);
 
     TRACE("progid is %s\n",debugstr_w(wstrProgID));
 
-    /* if we have a good string, write the stream */
-    if( wstrProgID )
-        r = STORAGE_WriteCompObj( pstg, &clsid, 
-                lpszUserType, szwClipName, wstrProgID );
-    else
-        r = E_OUTOFMEMORY;
+    r = STORAGE_WriteCompObj( pstg, &clsid, 
+                              lpszUserType, szwClipName, wstrProgID );
 
-    IMalloc_Free( allocator, wstrProgID);
+    CoTaskMemFree(wstrProgID);
 
     return r;
 }
@@ -6804,7 +7161,7 @@ HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lp
                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
     if( FAILED ( r ) )
     {
-        ERR("Failed to open stream\n");
+        WARN("Failed to open stream r = %08x\n", r);
         return r;
     }
 
@@ -6917,7 +7274,7 @@ HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName
             {
                 char strTemp[OLESTREAM_MAX_STR_LEN];
                 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
-                hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength));
+                hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
                 if(hErr == ERROR_SUCCESS)
                 {
                     strcpy(IStorageCompObj.strCLSIDName, strTemp);
@@ -6973,7 +7330,7 @@ HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName
  *     This function is used by OleConvertOLESTREAMToIStorage only.
  *
  */
-void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
+static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
 {
     HRESULT hRes;
     IStream *pStream;
@@ -7057,7 +7414,7 @@ void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD d
  *     Might need to verify the data and return appropriate error message
  *
  */
-void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
+static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
 {
     HRESULT hRes;
     IStream *pStream;
@@ -7096,7 +7453,7 @@ void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD d
  *
  *
  */
-HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
+static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
 {
     HRESULT hRes;
     IStream *pStream;
@@ -7166,7 +7523,7 @@ HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dw
  *
  *
  */
-void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
 {
 
     HRESULT hRes;
@@ -7193,7 +7550,7 @@ void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *
         IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
         if(pOleStreamData->dwDataLength > 0)
         {
-            pOleStreamData->pData = (LPSTR) HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
+            pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
             IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
         }
         IStream_Release(pStream);
@@ -7219,7 +7576,7 @@ void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *
  *
  *     Memory allocated for pData must be freed by the caller
  */
-void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
 {
     HRESULT hRes;
     IStream *pStream;
@@ -7282,7 +7639,7 @@ void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *
             MetaFilePict.hMF = 0;
 
             /* Get Metafile Data */
-            pOleStreamData[1].pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
+            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);
         }
@@ -7311,6 +7668,8 @@ HRESULT WINAPI OleConvertOLESTREAMToIStorage (
     HRESULT hRes=S_OK;
     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
 
+    TRACE("%p %p %p\n", pOleStream, pstg, ptd);
+
     memset(pOleStreamData, 0, sizeof(pOleStreamData));
 
     if(ptd != NULL)
@@ -7401,6 +7760,7 @@ HRESULT WINAPI OleConvertIStorageToOLESTREAM (
     OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
     static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
 
+    TRACE("%p %p\n", pstg, pOleStream);
 
     memset(pOleStreamData, 0, sizeof(pOleStreamData));
 
@@ -7458,6 +7818,14 @@ HRESULT WINAPI GetConvertStg(IStorage *stg) {
 
 /******************************************************************************
  * StgIsStorageFile [OLE32.@]
+ * Verify if the file contains a storage object
+ *
+ * PARAMS
+ *  fn      [ I] Filename
+ *
+ * RETURNS
+ *  S_OK    if file has magic bytes as a storage object
+ *  S_FALSE if file is not storage
  */
 HRESULT WINAPI
 StgIsStorageFile(LPCOLESTR fn)
@@ -7466,7 +7834,7 @@ StgIsStorageFile(LPCOLESTR fn)
        BYTE            magic[8];
        DWORD           bytes_read;
 
-       TRACE("(\'%s\')\n", debugstr_w(fn));
+       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);
@@ -7496,3 +7864,63 @@ StgIsStorageFile(LPCOLESTR fn)
        WARN(" -> Invalid header.\n");
        return S_FALSE;
 }
+
+/***********************************************************************
+ *             WriteClassStm (OLE32.@)
+ *
+ * Writes a CLSID to a stream.
+ *
+ * PARAMS
+ *  pStm   [I] Stream to write to.
+ *  rclsid [I] CLSID to write.
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: HRESULT code.
+ */
+HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
+{
+    TRACE("(%p,%p)\n",pStm,rclsid);
+
+    if (!pStm || !rclsid)
+        return E_INVALIDARG;
+
+    return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
+}
+
+/***********************************************************************
+ *             ReadClassStm (OLE32.@)
+ *
+ * Reads a CLSID from a stream.
+ *
+ * PARAMS
+ *  pStm   [I] Stream to read from.
+ *  rclsid [O] CLSID to read.
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: HRESULT code.
+ */
+HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
+{
+    ULONG nbByte;
+    HRESULT res;
+
+    TRACE("(%p,%p)\n",pStm,pclsid);
+
+    if (!pStm || !pclsid)
+        return E_INVALIDARG;
+
+    /* clear the output args */
+    memcpy(pclsid, &CLSID_NULL, sizeof(*pclsid));
+
+    res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
+
+    if (FAILED(res))
+        return res;
+
+    if (nbByte != sizeof(CLSID))
+        return STG_E_READFAULT;
+    else
+        return S_OK;
+}