Index: trunk/src/ole32/ole32.h
===================================================================
--- trunk/src/ole32/ole32.h	(revision 5024)
+++ trunk/src/ole32/ole32.h	(revision 5026)
@@ -1,3 +1,3 @@
-/* $Id: ole32.h,v 1.13 2000-12-24 14:41:15 sandervl Exp $ */
+/* $Id: ole32.h,v 1.14 2001-01-25 20:17:23 sandervl Exp $ */
 /*
  *
@@ -33,5 +33,7 @@
 #undef CALLCONV
 
+#ifdef __cplusplus
 #include <os2win.h>
+#endif
 #include <ole2ver.h>
 #include <ole.h>
Index: trunk/src/ole32/ole32.mak
===================================================================
--- trunk/src/ole32/ole32.mak	(revision 5024)
+++ trunk/src/ole32/ole32.mak	(revision 5026)
@@ -1,3 +1,3 @@
-# $Id: ole32.mak,v 1.3 2000-12-02 23:40:43 bird Exp $
+# $Id: ole32.mak,v 1.4 2001-01-25 20:17:23 sandervl Exp $
 
 #
@@ -50,5 +50,5 @@
 $(OBJDIR)\stg_bigblockfile.obj \
 $(OBJDIR)\stg_stream.obj \
-$(OBJDIR)\storage.obj \
+$(OBJDIR)\storage32.obj \
 $(OBJDIR)\stubs.obj \
 $(OBJDIR)\taskmem.obj \
Index: trunk/src/ole32/oleClip.cpp
===================================================================
--- trunk/src/ole32/oleClip.cpp	(revision 5024)
+++ trunk/src/ole32/oleClip.cpp	(revision 5026)
@@ -1,3 +1,3 @@
-/* $Id: oleClip.cpp,v 1.5 2000-11-24 10:29:40 sandervl Exp $ */
+/* $Id: oleClip.cpp,v 1.6 2001-01-25 20:17:23 sandervl Exp $ */
 /* 
  * 
@@ -60,5 +60,5 @@
 #include "oString.h"
 #include "heapstring.h"
-#include "storage.h"
+#include "storage32.h"
 #include <assert.h>
 
@@ -1010,5 +1010,5 @@
 
         lstrcpyWtoA(strOleTypeName, strProgID);
-        OLECONVERT_CreateEmbeddedOleStream(std.u.pstg);
+        OLECONVERT_CreateOleStream(std.u.pstg);
         OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
       }
Index: trunk/src/ole32/oleMenu.cpp
===================================================================
--- trunk/src/ole32/oleMenu.cpp	(revision 5024)
+++ trunk/src/ole32/oleMenu.cpp	(revision 5026)
@@ -1,3 +1,3 @@
-/* $Id: oleMenu.cpp,v 1.3 2000-09-17 10:31:06 davidr Exp $ */
+/* $Id: oleMenu.cpp,v 1.4 2001-01-25 20:17:24 sandervl Exp $ */
 /* 
  * 
@@ -22,4 +22,5 @@
 #include "oString.h"
 #include <assert.h>
+#include "storage32.h"
 
 // ======================================================================
Index: trunk/src/ole32/stg_bigblockfile.c
===================================================================
--- trunk/src/ole32/stg_bigblockfile.c	(revision 5026)
+++ trunk/src/ole32/stg_bigblockfile.c	(revision 5026)
@@ -0,0 +1,854 @@
+/******************************************************************************
+ *
+ * BigBlockFile
+ *
+ * This is the implementation of a file that consists of blocks of 
+ * a predetermined size.
+ * This class is used in the Compound File implementation of the 
+ * IStorage and IStream interfaces. It provides the functionality 
+ * to read and write any blocks in the file as well as setting and 
+ * obtaining the size of the file.
+ * The blocks are indexed sequentially from the start of the file
+ * starting with -1.
+ * 
+ * TODO:
+ * - Support for a transacted mode
+ *
+ * Copyright 1999 Thuy Nguyen
+ *
+ */
+
+#ifdef __WIN32OS2__
+#define WINE_LARGE_INTEGER
+#define inline
+
+#include <odin.h>
+#include "ole32.h"
+#include "heapstring.h"
+
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "wine/obj_storage.h"
+#include "ole2.h"
+
+#include "storage32.h"
+
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(storage);
+
+/***********************************************************
+ * Data structures used internally by the BigBlockFile
+ * class.
+ */
+
+/* We map in PAGE_SIZE-sized chunks. Must be a multiple of 4096. */
+#define PAGE_SIZE       131072
+
+#define BLOCKS_PER_PAGE (PAGE_SIZE / BIG_BLOCK_SIZE)
+
+/* We keep a list of recently-discarded pages. This controls the
+ * size of that list. */
+#define MAX_VICTIM_PAGES 16
+
+/* This structure provides one bit for each block in a page.
+ * Use BIGBLOCKFILE_{Test,Set,Clear}Bit to manipulate it. */
+typedef struct
+{
+    unsigned int bits[BLOCKS_PER_PAGE / (CHAR_BIT * sizeof(unsigned int))];
+} BlockBits;
+
+/***
+ * This structure identifies the paged that are mapped
+ * from the file and their position in memory. It is 
+ * also used to hold a reference count to those pages.
+ *
+ * page_index identifies which PAGE_SIZE chunk from the
+ * file this mapping represents. (The mappings are always
+ * PAGE_SIZE-aligned.)
+ */
+struct MappedPage
+{
+    MappedPage *next;
+    MappedPage *prev;
+
+    DWORD  page_index;
+    LPVOID lpBytes;
+    LONG   refcnt;
+
+    BlockBits readable_blocks;
+    BlockBits writable_blocks;
+};
+
+/***********************************************************
+ * Prototypes for private methods
+ */
+static void*     BIGBLOCKFILE_GetMappedView(LPBIGBLOCKFILE This,
+                                            DWORD          page_index);
+static void      BIGBLOCKFILE_ReleaseMappedPage(LPBIGBLOCKFILE This,
+                                                MappedPage *page);
+static void      BIGBLOCKFILE_FreeAllMappedPages(LPBIGBLOCKFILE This);
+static void      BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This);
+static void      BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This);
+static void*     BIGBLOCKFILE_GetBigBlockPointer(LPBIGBLOCKFILE This,
+                                                 ULONG          index,
+                                                 DWORD          desired_access);
+static MappedPage* BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This, 
+						   void*         pBlock);
+static MappedPage* BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This,
+					   ULONG page_index);
+static DWORD     BIGBLOCKFILE_GetProtectMode(DWORD openFlags);
+static BOOL      BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile);
+static BOOL      BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt);
+
+/* Note that this evaluates a and b multiple times, so don't
+ * pass expressions with side effects. */
+#define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b))
+
+/***********************************************************
+ * Blockbits functions.
+ */
+static inline BOOL BIGBLOCKFILE_TestBit(const BlockBits *bb,
+					unsigned int index)
+{
+    unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
+    unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
+
+    return bb->bits[array_index] & (1 << bit_index);
+}
+
+static inline void BIGBLOCKFILE_SetBit(BlockBits *bb, unsigned int index)
+{
+    unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
+    unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
+
+    bb->bits[array_index] |= (1 << bit_index);
+}
+
+static inline void BIGBLOCKFILE_ClearBit(BlockBits *bb, unsigned int index)
+{
+    unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
+    unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
+
+    bb->bits[array_index] &= ~(1 << bit_index);
+}
+
+static inline void BIGBLOCKFILE_Zero(BlockBits *bb)
+{
+    memset(bb->bits, 0, sizeof(bb->bits));
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_Construct
+ *
+ * Construct a big block file. Create the file mapping object. 
+ * Create the read only mapped pages list, the writable mapped page list
+ * and the blocks in use list.
+ */
+BigBlockFile * BIGBLOCKFILE_Construct(
+  HANDLE   hFile,
+  ILockBytes* pLkByt,
+  DWORD    openFlags,
+  ULONG    blocksize,
+  BOOL     fileBased)
+{
+  LPBIGBLOCKFILE This;
+
+  This = (LPBIGBLOCKFILE)HeapAlloc(GetProcessHeap(), 0, sizeof(BigBlockFile));
+
+  if (This == NULL)
+    return NULL;
+
+  This->fileBased = fileBased;
+
+  This->flProtect = BIGBLOCKFILE_GetProtectMode(openFlags);
+
+  This->blocksize = blocksize;
+
+  This->maplist = NULL;
+  This->victimhead = NULL;
+  This->victimtail = NULL;
+  This->num_victim_pages = 0;
+
+  if (This->fileBased)
+  {
+    if (!BIGBLOCKFILE_FileInit(This, hFile))
+    {
+      HeapFree(GetProcessHeap(), 0, This);
+      return NULL;
+    }
+  }
+  else
+  {
+    if (!BIGBLOCKFILE_MemInit(This, pLkByt))
+    {
+      HeapFree(GetProcessHeap(), 0, This);
+      return NULL;
+    }
+  }
+
+  return This;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_FileInit
+ *
+ * Initialize a big block object supported by a file.
+ */
+static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile)
+{
+  This->pLkbyt     = NULL;
+  This->hbytearray = 0;
+  This->pbytearray = NULL;
+
+  This->hfile = hFile;
+
+  if (This->hfile == INVALID_HANDLE_VALUE)
+    return FALSE;
+
+  /* create the file mapping object
+   */
+  This->hfilemap = CreateFileMappingA(This->hfile,
+                                      NULL,
+                                      This->flProtect,
+                                      0, 0,
+                                      NULL);
+
+  if (!This->hfilemap)
+  {
+    CloseHandle(This->hfile);
+    return FALSE;
+  }
+
+  This->filesize.s.LowPart = GetFileSize(This->hfile,
+					 &This->filesize.s.HighPart);
+
+  This->maplist = NULL;
+
+  TRACE("file len %lu\n", This->filesize.s.LowPart);
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_MemInit
+ *
+ * Initialize a big block object supported by an ILockBytes on HGLOABL.
+ */
+static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt)
+{
+  This->hfile       = 0;
+  This->hfilemap    = 0;
+
+  /*
+   * Retrieve the handle to the byte array from the LockByte object.
+   */
+  if (GetHGlobalFromILockBytes(plkbyt, &(This->hbytearray)) != S_OK)
+  {
+    FIXME("May not be an ILockBytes on HGLOBAL\n");
+    return FALSE;
+  }
+
+  This->pLkbyt = plkbyt;
+
+  /*
+   * Increment the reference count of the ILockByte object since
+   * we're keeping a reference to it.
+   */
+  ILockBytes_AddRef(This->pLkbyt);
+
+  This->filesize.s.LowPart = GlobalSize(This->hbytearray);
+  This->filesize.s.HighPart = 0;
+
+  This->pbytearray = GlobalLock(This->hbytearray);
+
+  TRACE("mem on %p len %lu\n", This->pbytearray, This->filesize.s.LowPart);
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_Destructor
+ *
+ * Destructor. Clean up, free memory.
+ */
+void BIGBLOCKFILE_Destructor(
+  LPBIGBLOCKFILE This)
+{
+  BIGBLOCKFILE_FreeAllMappedPages(This);
+
+  if (This->fileBased)
+  {
+    CloseHandle(This->hfilemap);
+    CloseHandle(This->hfile);
+  }
+  else
+  {
+    GlobalUnlock(This->hbytearray);
+    ILockBytes_Release(This->pLkbyt);
+  }
+
+  /* destroy this
+   */
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetROBigBlock
+ *
+ * Returns the specified block in read only mode.
+ * Will return NULL if the block doesn't exists.
+ */
+void* BIGBLOCKFILE_GetROBigBlock(
+  LPBIGBLOCKFILE This,
+  ULONG          index)
+{
+  /*
+   * block index starts at -1
+   * translate to zero based index
+   */
+  if (index == 0xffffffff)
+    index = 0;
+  else
+    index++;
+
+  /*
+   * validate the block index
+   * 
+   */
+  if (This->blocksize * (index + 1)
+      > ROUND_UP(This->filesize.s.LowPart, This->blocksize))
+  {
+    TRACE("out of range %lu vs %lu\n", This->blocksize * (index + 1),
+	  This->filesize.s.LowPart);
+    return NULL;
+  }
+
+  return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_READ);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetBigBlock
+ *
+ * Returns the specified block.
+ * Will grow the file if necessary.
+ */
+void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index)
+{
+  /*
+   * block index starts at -1
+   * translate to zero based index
+   */
+  if (index == 0xffffffff)
+    index = 0;
+  else
+    index++;
+
+  /*
+   * make sure that the block physically exists
+   */
+  if ((This->blocksize * (index + 1)) > This->filesize.s.LowPart)
+  {
+    ULARGE_INTEGER newSize;
+
+    newSize.s.HighPart = 0;
+    newSize.s.LowPart = This->blocksize * (index + 1);
+
+    BIGBLOCKFILE_SetSize(This, newSize);
+  }
+
+  return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_WRITE);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_ReleaseBigBlock
+ *
+ * Releases the specified block.
+ */
+void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock)
+{
+    MappedPage *page;
+
+    if (pBlock == NULL)
+	return;
+
+    page = BIGBLOCKFILE_GetPageFromPointer(This, pBlock);
+
+    if (page == NULL)
+	return;
+
+    BIGBLOCKFILE_ReleaseMappedPage(This, page);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_SetSize
+ *
+ * Sets the size of the file.
+ * 
+ */
+void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize)
+{
+  if (This->filesize.s.LowPart == newSize.s.LowPart)
+    return;
+
+  TRACE("from %lu to %lu\n", This->filesize.s.LowPart, newSize.s.LowPart);
+  /*
+   * unmap all views, must be done before call to SetEndFile
+   */
+  BIGBLOCKFILE_UnmapAllMappedPages(This);
+  
+  if (This->fileBased)
+  {
+    char buf[10];
+
+    /*
+     * close file-mapping object, must be done before call to SetEndFile
+     */
+    CloseHandle(This->hfilemap);
+    This->hfilemap = 0;
+
+    /*
+     * BEGIN HACK
+     * This fixes a bug when saving through smbfs.
+     * smbmount a Windows shared directory, save a structured storage file
+     * to that dir: crash.
+     *
+     * The problem is that the SetFilePointer-SetEndOfFile combo below
+     * doesn't always succeed. The file is not grown. It seems like the 
+     * operation is cached. By doing the WriteFile, the file is actually
+     * grown on disk.
+     * This hack is only needed when saving to smbfs.
+     */
+    memset(buf, '0', 10);
+    SetFilePointer(This->hfile, newSize.s.LowPart, NULL, FILE_BEGIN);
+    WriteFile(This->hfile, buf, 10, NULL, NULL);
+    /*
+     * END HACK 
+     */
+
+    /*
+     * set the new end of file
+     */
+    SetFilePointer(This->hfile, newSize.s.LowPart, NULL, FILE_BEGIN);
+    SetEndOfFile(This->hfile);
+  
+    /*
+     * re-create the file mapping object
+     */
+    This->hfilemap = CreateFileMappingA(This->hfile,
+                                        NULL,
+                                        This->flProtect,
+                                        0, 0, 
+                                        NULL);
+  }
+  else
+  {
+    GlobalUnlock(This->hbytearray);
+
+    /*
+     * Resize the byte array object.
+     */
+    ILockBytes_SetSize(This->pLkbyt, newSize);
+
+    /*
+     * Re-acquire the handle, it may have changed.
+     */
+    GetHGlobalFromILockBytes(This->pLkbyt, &This->hbytearray);
+    This->pbytearray = GlobalLock(This->hbytearray);
+  }
+
+  This->filesize.s.LowPart = newSize.s.LowPart;
+  This->filesize.s.HighPart = newSize.s.HighPart;
+
+  BIGBLOCKFILE_RemapAllMappedPages(This);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetSize
+ *
+ * Returns the size of the file.
+ * 
+ */
+ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This)
+{
+  return This->filesize;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_AccessCheck     [PRIVATE]
+ *
+ * block_index is the index within the page.
+ */
+static BOOL BIGBLOCKFILE_AccessCheck(MappedPage *page, ULONG block_index,
+				     DWORD desired_access)
+{
+    assert(block_index < BLOCKS_PER_PAGE);
+
+    if (desired_access == FILE_MAP_READ)
+    {
+	if (BIGBLOCKFILE_TestBit(&page->writable_blocks, block_index))
+	    return FALSE;
+
+	BIGBLOCKFILE_SetBit(&page->readable_blocks, block_index);
+    }
+    else
+    {
+	assert(desired_access == FILE_MAP_WRITE);
+
+	if (BIGBLOCKFILE_TestBit(&page->readable_blocks, block_index))
+	    return FALSE;
+
+	BIGBLOCKFILE_SetBit(&page->writable_blocks, block_index);
+    }
+
+    return TRUE;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetBigBlockPointer     [PRIVATE]
+ *
+ * Returns a pointer to the specified block.
+ */
+static void* BIGBLOCKFILE_GetBigBlockPointer(
+  LPBIGBLOCKFILE This, 
+  ULONG          block_index, 
+  DWORD          desired_access)
+{
+    DWORD page_index = block_index / BLOCKS_PER_PAGE;
+    DWORD block_on_page = block_index % BLOCKS_PER_PAGE;
+
+    MappedPage *page = BIGBLOCKFILE_GetMappedView(This, page_index);
+    if (!page || !page->lpBytes) return NULL;
+
+    if (!BIGBLOCKFILE_AccessCheck(page, block_on_page, desired_access))
+    {
+	BIGBLOCKFILE_ReleaseMappedPage(This, page);
+	return NULL;
+    }
+
+    return (LPBYTE)page->lpBytes + (block_on_page * This->blocksize);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetMappedPageFromPointer     [PRIVATE]
+ *
+ * pBlock is a pointer to a block on a page.
+ * The page has to be on the in-use list. (As oppsed to the victim list.)
+ *
+ * Does not increment the usage count.
+ */
+static MappedPage *BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This,
+						   void *pBlock)
+{
+    MappedPage *page;
+
+    for (page = This->maplist; page != NULL; page = page->next)
+    {
+	if ((LPBYTE)pBlock >= (LPBYTE)page->lpBytes
+	    && (LPBYTE)pBlock <= (LPBYTE)page->lpBytes + PAGE_SIZE)
+	    break;
+
+    }
+
+    return page;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_FindPageInList      [PRIVATE]
+ *
+ */
+static MappedPage *BIGBLOCKFILE_FindPageInList(MappedPage *head,
+					       ULONG page_index)
+{
+    for (; head != NULL; head = head->next)
+    {
+	if (head->page_index == page_index)
+	{
+	    InterlockedIncrement(&head->refcnt);
+	    break;
+	}
+    }
+
+    return head;
+
+}
+
+static void BIGBLOCKFILE_UnlinkPage(MappedPage *page)
+{
+    if (page->next) page->next->prev = page->prev;
+    if (page->prev) page->prev->next = page->next;
+}
+
+static void BIGBLOCKFILE_LinkHeadPage(MappedPage **head, MappedPage *page)
+{
+    if (*head) (*head)->prev = page;
+    page->next = *head;
+    page->prev = NULL;
+    *head = page;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetMappedView      [PRIVATE]
+ *
+ * Gets the page requested if it is already mapped.
+ * If it's not already mapped, this method will map it
+ */
+static void * BIGBLOCKFILE_GetMappedView(
+  LPBIGBLOCKFILE This,
+  DWORD          page_index)
+{
+    MappedPage *page;
+
+    page = BIGBLOCKFILE_FindPageInList(This->maplist, page_index);
+    if (!page)
+    {
+	page = BIGBLOCKFILE_FindPageInList(This->victimhead, page_index);
+	if (page)
+	{
+	    This->num_victim_pages--;
+
+	    BIGBLOCKFILE_Zero(&page->readable_blocks);
+	    BIGBLOCKFILE_Zero(&page->writable_blocks);
+	}
+    }
+
+    if (page)
+    {
+	/* If the page is not already at the head of the list, move
+	 * it there. (Also moves pages from victim to main list.) */
+	if (This->maplist != page)
+	{
+	    if (This->victimhead == page) This->victimhead = page->next;
+	    if (This->victimtail == page) This->victimtail = page->prev;
+
+	    BIGBLOCKFILE_UnlinkPage(page);
+
+	    BIGBLOCKFILE_LinkHeadPage(&This->maplist, page);
+	}
+
+	return page;
+    }
+
+    page = BIGBLOCKFILE_CreatePage(This, page_index);
+    if (!page) return NULL;
+
+    BIGBLOCKFILE_LinkHeadPage(&This->maplist, page);
+
+    return page;
+}
+
+static BOOL BIGBLOCKFILE_MapPage(LPBIGBLOCKFILE This, MappedPage *page)
+{
+    DWORD lowoffset = PAGE_SIZE * page->page_index;
+
+    if (This->fileBased)
+    {
+	DWORD numBytesToMap;
+	DWORD desired_access;
+
+	if (lowoffset + PAGE_SIZE > This->filesize.s.LowPart)
+	    numBytesToMap = This->filesize.s.LowPart - lowoffset;
+	else
+	    numBytesToMap = PAGE_SIZE;
+
+	if (This->flProtect == PAGE_READONLY)
+	    desired_access = FILE_MAP_READ;
+	else
+	    desired_access = FILE_MAP_WRITE;
+
+	page->lpBytes = MapViewOfFile(This->hfilemap, desired_access, 0,
+				      lowoffset, numBytesToMap);
+    }
+    else
+    {
+	page->lpBytes = (LPBYTE)This->pbytearray + lowoffset;
+    }
+
+    TRACE("mapped page %lu to %p\n", page->page_index, page->lpBytes);
+
+    return page->lpBytes != NULL;
+}
+
+static MappedPage *BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This,
+					   ULONG page_index)
+{
+    MappedPage *page;
+
+    page = HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage));
+    if (page == NULL)
+      return NULL;
+
+    page->page_index = page_index;
+    page->refcnt = 1;
+
+    page->next = NULL;
+    page->prev = NULL;
+
+    BIGBLOCKFILE_MapPage(This, page);
+
+    BIGBLOCKFILE_Zero(&page->readable_blocks);
+    BIGBLOCKFILE_Zero(&page->writable_blocks);
+
+    return page;
+}
+
+static void BIGBLOCKFILE_UnmapPage(LPBIGBLOCKFILE This, MappedPage *page)
+{
+    TRACE("%ld at %p\n", page->page_index, page->lpBytes);
+    if (page->refcnt > 0)
+	ERR("unmapping inuse page %p\n", page->lpBytes);
+
+    if (This->fileBased && page->lpBytes)
+	UnmapViewOfFile(page->lpBytes);
+
+    page->lpBytes = NULL;
+}
+
+static void BIGBLOCKFILE_DeletePage(LPBIGBLOCKFILE This, MappedPage *page)
+{
+    BIGBLOCKFILE_UnmapPage(This, page);
+
+    HeapFree(GetProcessHeap(), 0, page);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_ReleaseMappedPage      [PRIVATE]
+ *
+ * Decrements the reference count of the mapped page.
+ */
+static void BIGBLOCKFILE_ReleaseMappedPage(
+  LPBIGBLOCKFILE This,
+  MappedPage    *page)
+{
+    assert(This != NULL);
+    assert(page != NULL);
+
+    /* If the page is no longer refenced, move it to the victim list.
+     * If the victim list is too long, kick somebody off. */
+    if (!InterlockedDecrement(&page->refcnt))
+    {
+	if (This->maplist == page) This->maplist = page->next;
+
+	BIGBLOCKFILE_UnlinkPage(page);
+
+	if (MAX_VICTIM_PAGES > 0)
+	{
+	    if (This->num_victim_pages >= MAX_VICTIM_PAGES)
+	    {
+		MappedPage *victim = This->victimtail;
+		if (victim)
+		{
+		    This->victimtail = victim->prev;
+		    if (This->victimhead == victim)
+			This->victimhead = victim->next;
+
+		    BIGBLOCKFILE_UnlinkPage(victim);
+		    BIGBLOCKFILE_DeletePage(This, victim);
+		}
+	    }
+	    else This->num_victim_pages++;
+
+	    BIGBLOCKFILE_LinkHeadPage(&This->victimhead, page);
+	    if (This->victimtail == NULL) This->victimtail = page;
+	}
+	else
+	    BIGBLOCKFILE_DeletePage(This, page);
+    }
+}
+
+static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This, MappedPage *list)
+{
+    while (list != NULL)
+    {
+	MappedPage *next = list->next;
+
+	BIGBLOCKFILE_DeletePage(This, list);
+
+	list = next;
+    }
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_FreeAllMappedPages     [PRIVATE]
+ *
+ * Unmap all currently mapped pages.
+ * Empty mapped pages list.
+ */
+static void BIGBLOCKFILE_FreeAllMappedPages(
+  LPBIGBLOCKFILE This)
+{
+    BIGBLOCKFILE_DeleteList(This, This->maplist);
+    BIGBLOCKFILE_DeleteList(This, This->victimhead);
+
+    This->maplist = NULL;
+    This->victimhead = NULL;
+    This->victimtail = NULL;
+    This->num_victim_pages = 0;
+}
+
+static void BIGBLOCKFILE_UnmapList(LPBIGBLOCKFILE This, MappedPage *list)
+{
+    for (; list != NULL; list = list->next)
+    {
+	BIGBLOCKFILE_UnmapPage(This, list);
+    }
+}
+
+static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This)
+{
+    BIGBLOCKFILE_UnmapList(This, This->maplist);
+    BIGBLOCKFILE_UnmapList(This, This->victimhead);
+}
+
+static void BIGBLOCKFILE_RemapList(LPBIGBLOCKFILE This, MappedPage *list)
+{
+    while (list != NULL)
+    {
+	MappedPage *next = list->next;
+
+	if (list->page_index * PAGE_SIZE > This->filesize.s.LowPart)
+	{
+	    TRACE("discarding %lu\n", list->page_index);
+
+	    /* page is entirely outside of the file, delete it */
+	    BIGBLOCKFILE_UnlinkPage(list);
+	    BIGBLOCKFILE_DeletePage(This, list);
+	}
+	else
+	{
+	    /* otherwise, remap it */
+	    BIGBLOCKFILE_MapPage(This, list);
+	}
+
+	list = next;
+    }
+}
+
+static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This)
+{
+    BIGBLOCKFILE_RemapList(This, This->maplist);
+    BIGBLOCKFILE_RemapList(This, This->victimhead);
+}
+
+/****************************************************************************
+ *      BIGBLOCKFILE_GetProtectMode
+ *
+ * This function will return a protection mode flag for a file-mapping object
+ * from the open flags of a file.
+ */
+static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags)
+{
+    if (openFlags & (STGM_WRITE | STGM_READWRITE))
+	return PAGE_READWRITE;
+    else
+	return PAGE_READONLY;
+}
Index: trunk/src/ole32/stg_bigblockfile.cpp
===================================================================
--- trunk/src/ole32/stg_bigblockfile.cpp	(revision 5024)
+++ 	(revision )
@@ -1,838 +1,0 @@
-/* $Id: stg_bigblockfile.cpp,v 1.2 2000-03-19 15:33:07 davidr Exp $ */
-/* 
- * BigBlockFile
- * 
- * 12/03/00
- * 
- * Direct port of Wine Implementation
- *
- * This is the implementation of a file that consists of blocks of 
- * a predetermined size.
- * This class is used in the Compound File implementation of the 
- * IStorage and IStream interfaces. It provides the functionality 
- * to read and write any blocks in the file as well as setting and 
- * obtaining the size of the file.
- * The blocks are indexed sequentially from the start of the file
- * starting with -1.
- * 
- * TODO:
- * - Support for a transacted mode
- *
- * Copyright 1999 Thuy Nguyen
- */
-
-#include "ole32.h"
-#include "heapstring.h"
-#include "debugtools.h"
-#include "storage.h"
-
-#include <assert.h>
-
-#define CHAR_BIT 8	// (From EMX limits.h)
-
-/***********************************************************
- * Data structures used internally by the BigBlockFile
- * class.
- */
-
-/* We map in PAGE_SIZE-sized chunks. Must be a multiple of 4096. */
-#define PAGE_SIZE       131072
-
-#define BLOCKS_PER_PAGE (PAGE_SIZE / BIG_BLOCK_SIZE)
-
-/* We keep a list of recently-discarded pages. This controls the
- * size of that list. */
-#define MAX_VICTIM_PAGES 16
-
-/* This structure provides one bit for each block in a page.
- * Use BIGBLOCKFILE_{Test,Set,Clear}Bit to manipulate it. */
-typedef struct
-{
-    unsigned int bits[BLOCKS_PER_PAGE / (CHAR_BIT * sizeof(unsigned int))];
-} BlockBits;
-
-/***
- * This structure identifies the paged that are mapped
- * from the file and their position in memory. It is 
- * also used to hold a reference count to those pages.
- *
- * page_index identifies which PAGE_SIZE chunk from the
- * file this mapping represents. (The mappings are always
- * PAGE_SIZE-aligned.)
- */
-struct MappedPage
-{
-    MappedPage *next;
-    MappedPage *prev;
-
-    DWORD  page_index;
-    LPVOID lpBytes;
-    LONG   refcnt;
-
-    BlockBits readable_blocks;
-    BlockBits writable_blocks;
-};
-
-/***********************************************************
- * Prototypes for private methods
- */
-static void*     BIGBLOCKFILE_GetMappedView(LPBIGBLOCKFILE This,
-                                            DWORD          page_index);
-static void      BIGBLOCKFILE_ReleaseMappedPage(LPBIGBLOCKFILE This,
-                                                MappedPage *page);
-static void      BIGBLOCKFILE_FreeAllMappedPages(LPBIGBLOCKFILE This);
-static void      BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This);
-static void      BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This);
-static void*     BIGBLOCKFILE_GetBigBlockPointer(LPBIGBLOCKFILE This,
-                                                 ULONG          index,
-                                                 DWORD          desired_access);
-static MappedPage* BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This, 
-						   void*         pBlock);
-static MappedPage* BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This,
-					   ULONG page_index);
-static DWORD     BIGBLOCKFILE_GetProtectMode(DWORD openFlags);
-static BOOL      BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile);
-static BOOL      BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt);
-
-/* Note that this evaluates a and b multiple times, so don't
- * pass expressions with side effects. */
-#define ROUND_UP(a, b) (!(a) ? 0 : ((a) + (b) - (((a)-1) % (b)) - 1))
-
-/***********************************************************
- * Blockbits functions.
- */
-static inline BOOL BIGBLOCKFILE_TestBit(const BlockBits *bb,
-					unsigned int index)
-{
-    unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
-    unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
-
-    return bb->bits[array_index] & (1 << bit_index);
-}
-
-static inline void BIGBLOCKFILE_SetBit(BlockBits *bb, unsigned int index)
-{
-    unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
-    unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
-
-    bb->bits[array_index] |= (1 << bit_index);
-}
-
-static inline void BIGBLOCKFILE_ClearBit(BlockBits *bb, unsigned int index)
-{
-    unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
-    unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
-
-    bb->bits[array_index] &= ~(1 << bit_index);
-}
-
-static inline void BIGBLOCKFILE_Zero(BlockBits *bb)
-{
-    memset(bb->bits, 0, sizeof(bb->bits));
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_Construct
- *
- * Construct a big block file. Create the file mapping object. 
- * Create the read only mapped pages list, the writable mapped page list
- * and the blocks in use list.
- */
-BigBlockFile * BIGBLOCKFILE_Construct(
-  HANDLE   hFile,
-  ILockBytes* pLkByt,
-  DWORD    openFlags,
-  ULONG    blocksize,
-  BOOL     fileBased)
-{
-  LPBIGBLOCKFILE This;
-
-  This = (LPBIGBLOCKFILE)HeapAlloc(GetProcessHeap(), 0, sizeof(BigBlockFile));
-
-  if (This == NULL)
-    return NULL;
-
-  This->fileBased = fileBased;
-
-  This->flProtect = BIGBLOCKFILE_GetProtectMode(openFlags);
-
-  This->blocksize = blocksize;
-
-  This->maplist = NULL;
-  This->victimhead = NULL;
-  This->victimtail = NULL;
-  This->num_victim_pages = 0;
-
-  if (This->fileBased)
-  {
-    if (!BIGBLOCKFILE_FileInit(This, hFile))
-    {
-      HeapFree(GetProcessHeap(), 0, This);
-      return NULL;
-    }
-  }
-  else
-  {
-    if (!BIGBLOCKFILE_MemInit(This, pLkByt))
-    {
-      HeapFree(GetProcessHeap(), 0, This);
-      return NULL;
-    }
-  }
-
-  return This;
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_FileInit
- *
- * Initialize a big block object supported by a file.
- */
-static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile)
-{
-  This->pLkbyt     = NULL;
-  This->hbytearray = 0;
-  This->pbytearray = NULL;
-
-  This->hfile = hFile;
-
-  if (This->hfile == INVALID_HANDLE_VALUE)
-    return FALSE;
-
-  /* create the file mapping object
-   */
-  This->hfilemap = CreateFileMappingA(This->hfile,
-                                      NULL,
-                                      This->flProtect,
-                                      0, 0,
-                                      NULL);
-
-  if (This->hfilemap == NULL)
-  {
-    CloseHandle(This->hfile);
-    return FALSE;
-  }
-
-  This->filesize.LowPart = GetFileSize(This->hfile,
-					 (LPDWORD)&This->filesize.HighPart);
-
-  This->maplist = NULL;
-
-  TRACE("file len %lu\n", This->filesize.LowPart);
-
-  return TRUE;
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_MemInit
- *
- * Initialize a big block object supported by an ILockBytes on HGLOABL.
- */
-static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt)
-{
-  This->hfile       = 0;
-  This->hfilemap    = NULL;
-
-  /*
-   * Retrieve the handle to the byte array from the LockByte object.
-   */
-  if (GetHGlobalFromILockBytes(plkbyt, &(This->hbytearray)) != S_OK)
-  {
-    FIXME("May not be an ILockBytes on HGLOBAL\n");
-    return FALSE;
-  }
-
-  This->pLkbyt = plkbyt;
-
-  /*
-   * Increment the reference count of the ILockByte object since
-   * we're keeping a reference to it.
-   */
-  ILockBytes_AddRef(This->pLkbyt);
-
-  This->filesize.LowPart = GlobalSize(This->hbytearray);
-  This->filesize.HighPart = 0;
-
-  This->pbytearray = GlobalLock(This->hbytearray);
-
-  TRACE("mem on %p len %lu\n", This->pbytearray, This->filesize.LowPart);
-
-  return TRUE;
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_Destructor
- *
- * Destructor. Clean up, free memory.
- */
-void BIGBLOCKFILE_Destructor(
-  LPBIGBLOCKFILE This)
-{
-  BIGBLOCKFILE_FreeAllMappedPages(This);
-
-  if (This->fileBased)
-  {
-    CloseHandle(This->hfilemap);
-    CloseHandle(This->hfile);
-  }
-  else
-  {
-    GlobalUnlock(This->hbytearray);
-    ILockBytes_Release(This->pLkbyt);
-  }
-
-  /* destroy this
-   */
-  HeapFree(GetProcessHeap(), 0, This);
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_GetROBigBlock
- *
- * Returns the specified block in read only mode.
- * Will return NULL if the block doesn't exists.
- */
-void* BIGBLOCKFILE_GetROBigBlock(
-  LPBIGBLOCKFILE This,
-  ULONG          index)
-{
-  /*
-   * block index starts at -1
-   * translate to zero based index
-   */
-  if (index == 0xffffffff)
-    index = 0;
-  else
-    index++;
-
-  /*
-   * validate the block index
-   * 
-   */
-  if (This->blocksize * (index + 1)
-      > ROUND_UP(This->filesize.LowPart, This->blocksize))
-  {
-    TRACE("out of range %lu vs %lu\n", This->blocksize * (index + 1),
-	  This->filesize.LowPart);
-    return NULL;
-  }
-
-  return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_READ);
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_GetBigBlock
- *
- * Returns the specified block.
- * Will grow the file if necessary.
- */
-void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index)
-{
-  /*
-   * block index starts at -1
-   * translate to zero based index
-   */
-  if (index == 0xffffffff)
-    index = 0;
-  else
-    index++;
-
-  /*
-   * make sure that the block physically exists
-   */
-  if ((This->blocksize * (index + 1)) > This->filesize.LowPart)
-  {
-    ULARGE_INTEGER newSize;
-
-    newSize.HighPart = 0;
-    newSize.LowPart = This->blocksize * (index + 1);
-
-    BIGBLOCKFILE_SetSize(This, newSize);
-  }
-
-  return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_WRITE);
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_ReleaseBigBlock
- *
- * Releases the specified block.
- */
-void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock)
-{
-    MappedPage *page;
-
-    if (pBlock == NULL)
-	return;
-
-    page = BIGBLOCKFILE_GetPageFromPointer(This, pBlock);
-
-    if (page == NULL)
-	return;
-
-    BIGBLOCKFILE_ReleaseMappedPage(This, page);
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_SetSize
- *
- * Sets the size of the file.
- * 
- */
-void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize)
-{
-  if (This->filesize.LowPart == newSize.LowPart)
-    return;
-
-  TRACE("from %lu to %lu\n", This->filesize.LowPart, newSize.LowPart);
-  /*
-   * unmap all views, must be done before call to SetEndFile
-   */
-  BIGBLOCKFILE_UnmapAllMappedPages(This);
-  
-  if (This->fileBased)
-  {
-    char buf[10];
-
-    /*
-     * close file-mapping object, must be done before call to SetEndFile
-     */
-    CloseHandle(This->hfilemap);
-    This->hfilemap = NULL;
-
-    /*
-     * BEGIN HACK
-     * This fixes a bug when saving through smbfs.
-     * smbmount a Windows shared directory, save a structured storage file
-     * to that dir: crash.
-     *
-     * The problem is that the SetFilePointer-SetEndOfFile combo below
-     * doesn't always succeed. The file is not grown. It seems like the 
-     * operation is cached. By doing the WriteFile, the file is actually
-     * grown on disk.
-     * This hack is only needed when saving to smbfs.
-     */
-    memset(buf, '0', 10);
-    SetFilePointer(This->hfile, newSize.LowPart, NULL, FILE_BEGIN);
-    WriteFile(This->hfile, buf, 10, NULL, NULL);
-    /*
-     * END HACK 
-     */
-  
-    /*
-     * set the new end of file
-     */
-    SetFilePointer(This->hfile, newSize.LowPart, NULL, FILE_BEGIN);
-    SetEndOfFile(This->hfile);
-  
-    /*
-     * re-create the file mapping object
-     */
-    This->hfilemap = CreateFileMappingA(This->hfile,
-                                        NULL,
-                                        This->flProtect,
-                                        0, 0, 
-                                        NULL);
-  }
-  else
-  {
-    GlobalUnlock(This->hbytearray);
-
-    /*
-     * Resize the byte array object.
-     */
-    ILockBytes_SetSize(This->pLkbyt, newSize);
-
-    /*
-     * Re-acquire the handle, it may have changed.
-     */
-    GetHGlobalFromILockBytes(This->pLkbyt, &This->hbytearray);
-    This->pbytearray = GlobalLock(This->hbytearray);
-  }
-
-  This->filesize.LowPart = newSize.LowPart;
-  This->filesize.HighPart = newSize.HighPart;
-
-  BIGBLOCKFILE_RemapAllMappedPages(This);
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_GetSize
- *
- * Returns the size of the file.
- * 
- */
-ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This)
-{
-  return This->filesize;
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_AccessCheck     [PRIVATE]
- *
- * block_index is the index within the page.
- */
-static BOOL BIGBLOCKFILE_AccessCheck(MappedPage *page, ULONG block_index,
-				     DWORD desired_access)
-{
-    assert(block_index < BLOCKS_PER_PAGE);
-
-    if (desired_access == FILE_MAP_READ)
-    {
-	if (BIGBLOCKFILE_TestBit(&page->writable_blocks, block_index))
-	    return FALSE;
-
-	BIGBLOCKFILE_SetBit(&page->readable_blocks, block_index);
-    }
-    else
-    {
-	assert(desired_access == FILE_MAP_WRITE);
-
-	if (BIGBLOCKFILE_TestBit(&page->readable_blocks, block_index))
-	    return FALSE;
-
-	BIGBLOCKFILE_SetBit(&page->writable_blocks, block_index);
-    }
-
-    return TRUE;
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_GetBigBlockPointer     [PRIVATE]
- *
- * Returns a pointer to the specified block.
- */
-static void* BIGBLOCKFILE_GetBigBlockPointer(
-  LPBIGBLOCKFILE This, 
-  ULONG          block_index, 
-  DWORD          desired_access)
-{
-    DWORD page_index = block_index / BLOCKS_PER_PAGE;
-    DWORD block_on_page = block_index % BLOCKS_PER_PAGE;
-
-    MappedPage *page = (MappedPage *)BIGBLOCKFILE_GetMappedView(This, page_index);
-    if (!page || !page->lpBytes) return NULL;
-
-    if (!BIGBLOCKFILE_AccessCheck(page, block_on_page, desired_access))
-    {
-	BIGBLOCKFILE_ReleaseMappedPage(This, page);
-	return NULL;
-    }
-
-    return (LPBYTE)page->lpBytes + (block_on_page * This->blocksize);
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_GetMappedPageFromPointer     [PRIVATE]
- *
- * pBlock is a pointer to a block on a page.
- * The page has to be on the in-use list. (As oppsed to the victim list.)
- *
- * Does not increment the usage count.
- */
-static MappedPage *BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This,
-						   void *pBlock)
-{
-    MappedPage *page;
-
-    for (page = This->maplist; page != NULL; page = page->next)
-    {
-	if ((LPBYTE)pBlock >= (LPBYTE)page->lpBytes
-	    && (LPBYTE)pBlock <= (LPBYTE)page->lpBytes + PAGE_SIZE)
-	    break;
-
-    }
-
-    return page;
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_FindPageInList      [PRIVATE]
- *
- */
-static MappedPage *BIGBLOCKFILE_FindPageInList(MappedPage *head,
-					       ULONG page_index)
-{
-    for (; head != NULL; head = head->next)
-    {
-	if (head->page_index == page_index)
-	{
-	    InterlockedIncrement(&head->refcnt);
-	    break;
-	}
-    }
-
-    return head;
-
-}
-
-static void BIGBLOCKFILE_UnlinkPage(MappedPage *page)
-{
-    if (page->next) page->next->prev = page->prev;
-    if (page->prev) page->prev->next = page->next;
-}
-
-static void BIGBLOCKFILE_LinkHeadPage(MappedPage **head, MappedPage *page)
-{
-    if (*head) (*head)->prev = page;
-    page->next = *head;
-    page->prev = NULL;
-    *head = page;
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_GetMappedView      [PRIVATE]
- *
- * Gets the page requested if it is already mapped.
- * If it's not already mapped, this method will map it
- */
-static void * BIGBLOCKFILE_GetMappedView(
-  LPBIGBLOCKFILE This,
-  DWORD          page_index)
-{
-    MappedPage *page;
-
-    page = BIGBLOCKFILE_FindPageInList(This->maplist, page_index);
-    if (!page)
-    {
-	page = BIGBLOCKFILE_FindPageInList(This->victimhead, page_index);
-	if (page)
-	{
-	    This->num_victim_pages--;
-
-	    BIGBLOCKFILE_Zero(&page->readable_blocks);
-	    BIGBLOCKFILE_Zero(&page->writable_blocks);
-	}
-    }
-
-    if (page)
-    {
-	/* If the page is not already at the head of the list, move
-	 * it there. (Also moves pages from victim to main list.) */
-	if (This->maplist != page)
-	{
-	    if (This->victimhead == page) This->victimhead = page->next;
-	    if (This->victimtail == page) This->victimtail = page->prev;
-
-	    BIGBLOCKFILE_UnlinkPage(page);
-
-	    BIGBLOCKFILE_LinkHeadPage(&This->maplist, page);
-	}
-
-	return page;
-    }
-
-    page = BIGBLOCKFILE_CreatePage(This, page_index);
-    if (!page) return NULL;
-
-    BIGBLOCKFILE_LinkHeadPage(&This->maplist, page);
-
-    return page;
-}
-
-static BOOL BIGBLOCKFILE_MapPage(LPBIGBLOCKFILE This, MappedPage *page)
-{
-    DWORD lowoffset = PAGE_SIZE * page->page_index;
-
-    if (This->fileBased)
-    {
-	DWORD numBytesToMap;
-	DWORD desired_access;
-
-	if (lowoffset + PAGE_SIZE > This->filesize.LowPart)
-	    numBytesToMap = This->filesize.LowPart - lowoffset;
-	else
-	    numBytesToMap = PAGE_SIZE;
-
-	if (This->flProtect == PAGE_READONLY)
-	    desired_access = FILE_MAP_READ;
-	else
-	    desired_access = FILE_MAP_WRITE;
-
-	page->lpBytes = MapViewOfFile(This->hfilemap, desired_access, 0,
-				      lowoffset, numBytesToMap);
-    }
-    else
-    {
-	page->lpBytes = (LPBYTE)This->pbytearray + lowoffset;
-    }
-
-    TRACE("mapped page %lu to %p\n", page->page_index, page->lpBytes);
-
-    return page->lpBytes != NULL;
-}
-
-static MappedPage *BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This,
-					   ULONG page_index)
-{
-    MappedPage *page;
-
-    page = (MappedPage *)HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage));
-    if (page == NULL)
-      return NULL;
-
-    page->page_index = page_index;
-    page->refcnt = 1;
-
-    page->next = NULL;
-    page->prev = NULL;
-
-    BIGBLOCKFILE_MapPage(This, page);
-
-    BIGBLOCKFILE_Zero(&page->readable_blocks);
-    BIGBLOCKFILE_Zero(&page->writable_blocks);
-
-    return page;
-}
-
-static void BIGBLOCKFILE_UnmapPage(LPBIGBLOCKFILE This, MappedPage *page)
-{
-    TRACE("%ld at %p\n", page->page_index, page->lpBytes);
-    if (page->refcnt > 0)
-	ERR("unmapping inuse page %p\n", page->lpBytes);
-
-    if (This->fileBased && page->lpBytes)
-	UnmapViewOfFile(page->lpBytes);
-
-    page->lpBytes = NULL;
-}
-
-static void BIGBLOCKFILE_DeletePage(LPBIGBLOCKFILE This, MappedPage *page)
-{
-    BIGBLOCKFILE_UnmapPage(This, page);
-
-    HeapFree(GetProcessHeap(), 0, page);
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_ReleaseMappedPage      [PRIVATE]
- *
- * Decrements the reference count of the mapped page.
- */
-static void BIGBLOCKFILE_ReleaseMappedPage(
-  LPBIGBLOCKFILE This,
-  MappedPage    *page)
-{
-    assert(This != NULL);
-    assert(page != NULL);
-
-    /* If the page is no longer refenced, move it to the victim list.
-     * If the victim list is too long, kick somebody off. */
-    if (!InterlockedDecrement(&page->refcnt))
-    {
-	if (This->maplist == page) This->maplist = page->next;
-
-	BIGBLOCKFILE_UnlinkPage(page);
-
-	if (MAX_VICTIM_PAGES > 0)
-	{
-	    if (This->num_victim_pages >= MAX_VICTIM_PAGES)
-	    {
-		MappedPage *victim = This->victimtail;
-		if (victim)
-		{
-		    This->victimtail = victim->prev;
-		    if (This->victimhead == victim)
-			This->victimhead = victim->next;
-
-		    BIGBLOCKFILE_UnlinkPage(victim);
-		    BIGBLOCKFILE_DeletePage(This, victim);
-		}
-	    }
-	    else This->num_victim_pages++;
-
-	    BIGBLOCKFILE_LinkHeadPage(&This->victimhead, page);
-	    if (This->victimtail == NULL) This->victimtail = page;
-	}
-	else
-	    BIGBLOCKFILE_DeletePage(This, page);
-    }
-}
-
-static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This, MappedPage *list)
-{
-    while (list != NULL)
-    {
-	MappedPage *next = list->next;
-
-	BIGBLOCKFILE_DeletePage(This, list);
-
-	list = next;
-    }
-}
-
-/******************************************************************************
- *      BIGBLOCKFILE_FreeAllMappedPages     [PRIVATE]
- *
- * Unmap all currently mapped pages.
- * Empty mapped pages list.
- */
-static void BIGBLOCKFILE_FreeAllMappedPages(
-  LPBIGBLOCKFILE This)
-{
-    BIGBLOCKFILE_DeleteList(This, This->maplist);
-    BIGBLOCKFILE_DeleteList(This, This->victimhead);
-
-    This->maplist = NULL;
-    This->victimhead = NULL;
-    This->victimtail = NULL;
-    This->num_victim_pages = 0;
-}
-
-static void BIGBLOCKFILE_UnmapList(LPBIGBLOCKFILE This, MappedPage *list)
-{
-    for (; list != NULL; list = list->next)
-    {
-	BIGBLOCKFILE_UnmapPage(This, list);
-    }
-}
-
-static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This)
-{
-    BIGBLOCKFILE_UnmapList(This, This->maplist);
-    BIGBLOCKFILE_UnmapList(This, This->victimhead);
-}
-
-static void BIGBLOCKFILE_RemapList(LPBIGBLOCKFILE This, MappedPage *list)
-{
-    while (list != NULL)
-    {
-	MappedPage *next = list->next;
-
-	if (list->page_index * PAGE_SIZE > This->filesize.LowPart)
-	{
-	    TRACE("discarding %lu\n", list->page_index);
-
-	    /* page is entirely outside of the file, delete it */
-	    BIGBLOCKFILE_UnlinkPage(list);
-	    BIGBLOCKFILE_DeletePage(This, list);
-	}
-	else
-	{
-	    /* otherwise, remap it */
-	    BIGBLOCKFILE_MapPage(This, list);
-	}
-
-	list = next;
-    }
-}
-
-static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This)
-{
-    BIGBLOCKFILE_RemapList(This, This->maplist);
-    BIGBLOCKFILE_RemapList(This, This->victimhead);
-}
-
-/****************************************************************************
- *      BIGBLOCKFILE_GetProtectMode
- *
- * This function will return a protection mode flag for a file-mapping object
- * from the open flags of a file.
- */
-static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags)
-{
-    if (openFlags & (STGM_WRITE | STGM_READWRITE))
-	return PAGE_READWRITE;
-    else
-	return PAGE_READONLY;
-}
Index: trunk/src/ole32/stg_stream.c
===================================================================
--- trunk/src/ole32/stg_stream.c	(revision 5026)
+++ trunk/src/ole32/stg_stream.c	(revision 5026)
@@ -0,0 +1,887 @@
+/*
+ * Compound Storage (32 bit version)
+ * Stream implementation
+ *
+ * This file contains the implementation of the stream interface
+ * for streams contained in a compound storage.
+ *
+ * Copyright 1999 Francis Beaudet
+ * Copyright 1999 Thuy Nguyen
+ */
+#ifdef __WIN32OS2__
+#define WINE_LARGE_INTEGER
+
+#include <odin.h>
+#include "ole32.h"
+#include "heapstring.h"
+
+#endif
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "winbase.h"
+#include "winerror.h"
+#include "ntddk.h"
+#include "debugtools.h"
+
+#include "storage32.h"
+
+DEFAULT_DEBUG_CHANNEL(storage);
+
+
+/*
+ * Virtual function table for the StgStreamImpl class.
+ */
+static ICOM_VTABLE(IStream) StgStreamImpl_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    StgStreamImpl_QueryInterface,
+    StgStreamImpl_AddRef,
+    StgStreamImpl_Release,
+    StgStreamImpl_Read,
+    StgStreamImpl_Write,
+    StgStreamImpl_Seek,
+    StgStreamImpl_SetSize,
+    StgStreamImpl_CopyTo,
+    StgStreamImpl_Commit,
+    StgStreamImpl_Revert,
+    StgStreamImpl_LockRegion,
+    StgStreamImpl_UnlockRegion,
+    StgStreamImpl_Stat,
+    StgStreamImpl_Clone
+};
+
+/******************************************************************************
+** StgStreamImpl implementation
+*/
+
+/***
+ * This is the constructor for the StgStreamImpl class.
+ *
+ * Params:
+ *    parentStorage - Pointer to the storage that contains the stream to open
+ *    ownerProperty - Index of the property that points to this stream.
+ */
+StgStreamImpl* StgStreamImpl_Construct(
+		StorageBaseImpl* parentStorage,
+    DWORD            grfMode,
+    ULONG            ownerProperty)
+{
+  StgStreamImpl* newStream;
+
+  newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl));
+  
+  if (newStream!=0)
+  {
+    /*
+     * Set-up the virtual function table and reference count.
+     */
+    ICOM_VTBL(newStream) = &StgStreamImpl_Vtbl;
+    newStream->ref       = 0;
+    
+    /*
+     * We want to nail-down the reference to the storage in case the
+     * stream out-lives the storage in the client application.
+     */
+    newStream->parentStorage = parentStorage;
+    IStorage_AddRef((IStorage*)newStream->parentStorage);
+
+    newStream->grfMode = grfMode;    
+    newStream->ownerProperty = ownerProperty;
+    
+    /*
+     * Start the stream at the begining.
+     */
+    newStream->currentPosition.s.HighPart = 0;
+    newStream->currentPosition.s.LowPart = 0;
+    
+    /*
+     * Initialize the rest of the data.
+     */
+    newStream->streamSize.s.HighPart = 0;
+    newStream->streamSize.s.LowPart  = 0;
+    newStream->bigBlockChain       = 0;
+    newStream->smallBlockChain     = 0;
+    
+    /*
+     * Read the size from the property and determine if the blocks forming
+     * this stream are large or small.
+     */
+    StgStreamImpl_OpenBlockChain(newStream);
+  }
+  
+  return newStream;
+}
+
+/***
+ * This is the destructor of the StgStreamImpl class.
+ *
+ * This method will clean-up all the resources used-up by the given StgStreamImpl 
+ * class. The pointer passed-in to this function will be freed and will not
+ * be valid anymore.
+ */
+void StgStreamImpl_Destroy(StgStreamImpl* This)
+{
+  TRACE("(%p)\n", This);
+
+  /*
+   * Release the reference we are holding on the parent storage.
+   */
+  IStorage_Release((IStorage*)This->parentStorage);
+  This->parentStorage = 0;
+
+  /*
+   * Make sure we clean-up the block chain stream objects that we were using.
+   */
+  if (This->bigBlockChain != 0)
+  {
+    BlockChainStream_Destroy(This->bigBlockChain);
+    This->bigBlockChain = 0;
+  }
+
+  if (This->smallBlockChain != 0)
+  {
+    SmallBlockChainStream_Destroy(This->smallBlockChain);
+    This->smallBlockChain = 0;
+  }
+
+  /*
+   * Finally, free the memory used-up by the class.
+   */
+  HeapFree(GetProcessHeap(), 0, This);  
+}
+
+/***
+ * This implements the IUnknown method QueryInterface for this
+ * class
+ */
+HRESULT WINAPI StgStreamImpl_QueryInterface(
+		  IStream*     iface,
+		  REFIID         riid,	      /* [in] */          
+		  void**         ppvObject)   /* [iid_is][out] */ 
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (ppvObject==0)
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+  
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = (IStream*)This;
+  }
+  else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0) 
+  {
+    *ppvObject = (IStream*)This;
+  }
+  
+  /*
+   * 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
+   */
+  StgStreamImpl_AddRef(iface);
+  
+  return S_OK;;
+}
+
+/***
+ * This implements the IUnknown method AddRef for this
+ * class
+ */
+ULONG WINAPI StgStreamImpl_AddRef(
+		IStream* iface)
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  This->ref++;
+  
+  return This->ref;
+}
+
+/***
+ * This implements the IUnknown method Release for this
+ * class
+ */
+ULONG WINAPI StgStreamImpl_Release(
+		IStream* iface)
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  ULONG newRef;
+  
+  This->ref--;
+  
+  newRef = This->ref;
+  
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (newRef==0)
+  {
+    StgStreamImpl_Destroy(This);
+  }
+  
+  return newRef;
+}
+
+/***
+ * This method will open the block chain pointed by the property
+ * that describes the stream.
+ * If the stream's size is null, no chain is opened.
+ */
+void StgStreamImpl_OpenBlockChain(
+        StgStreamImpl* This)
+{
+  StgProperty    curProperty;
+  BOOL         readSucessful;
+
+  /*
+   * Make sure no old object is staying behind.
+   */
+  if (This->smallBlockChain != 0)
+  {
+    SmallBlockChainStream_Destroy(This->smallBlockChain);
+    This->smallBlockChain = 0;
+  }
+
+  if (This->bigBlockChain != 0)
+  {
+    BlockChainStream_Destroy(This->bigBlockChain);
+    This->bigBlockChain = 0;
+  }
+
+  /*
+   * Read the information from the property.
+   */
+  readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
+					     This->ownerProperty,
+					     &curProperty);
+  
+  if (readSucessful)
+  {
+    This->streamSize = curProperty.size;
+    
+    /*
+     * This code supports only streams that are <32 bits in size.
+     */
+    assert(This->streamSize.s.HighPart == 0);
+    
+    if(curProperty.startingBlock == BLOCK_END_OF_CHAIN)
+    {
+      assert( (This->streamSize.s.HighPart == 0) && (This->streamSize.s.LowPart == 0) );
+    }
+    else
+    {
+      if ( (This->streamSize.s.HighPart == 0) &&
+	   (This->streamSize.s.LowPart < LIMIT_TO_USE_SMALL_BLOCK) )
+      {
+	This->smallBlockChain = SmallBlockChainStream_Construct(
+								This->parentStorage->ancestorStorage,	
+								This->ownerProperty);
+      }
+      else
+      {
+	This->bigBlockChain = BlockChainStream_Construct(
+							 This->parentStorage->ancestorStorage,
+							 NULL,
+							 This->ownerProperty);
+      }
+    }
+  }
+}
+
+/***
+ * This method is part of the ISequentialStream interface.
+ *
+ * If reads a block of information from the stream at the current
+ * position. It then moves the current position at the end of the
+ * read block
+ *
+ * See the documentation of ISequentialStream for more info.
+ */
+HRESULT WINAPI StgStreamImpl_Read( 
+		  IStream*     iface,
+		  void*          pv,        /* [length_is][size_is][out] */
+		  ULONG          cb,        /* [in] */                     
+		  ULONG*         pcbRead)   /* [out] */                    
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  ULONG bytesReadBuffer;
+  ULONG bytesToReadFromBuffer;
+
+  TRACE("(%p, %p, %ld, %p)\n",
+	iface, pv, cb, pcbRead);
+
+  /* 
+   * If the caller is not interested in the nubmer of bytes read,
+   * we use another buffer to avoid "if" statements in the code.
+   */
+  if (pcbRead==0)
+    pcbRead = &bytesReadBuffer;
+  
+  /*
+   * Using the known size of the stream, calculate the number of bytes
+   * to read from the block chain
+   */
+  bytesToReadFromBuffer = min( This->streamSize.s.LowPart - This->currentPosition.s.LowPart, cb);
+  
+  /*
+   * Depending on the type of chain that was opened when the stream was constructed,
+   * we delegate the work to the method that read the block chains.
+   */
+  if (This->smallBlockChain!=0)
+  {
+    SmallBlockChainStream_ReadAt(This->smallBlockChain,
+				 This->currentPosition,
+				 bytesToReadFromBuffer,
+				 pv,
+				 pcbRead);
+    
+  }
+  else if (This->bigBlockChain!=0)
+  {
+    BlockChainStream_ReadAt(This->bigBlockChain,
+			    This->currentPosition,
+			    bytesToReadFromBuffer,
+			    pv,
+			    pcbRead);
+  }
+  else
+  {
+    /*
+     * Small and big block chains are both NULL. This case will happen
+     * when a stream starts with BLOCK_END_OF_CHAIN and has size zero.
+     */
+
+    *pcbRead = 0;
+    return S_OK;
+  }
+
+  /*
+   * We should always be able to read the proper amount of data from the
+   * chain.
+   */
+  assert(bytesToReadFromBuffer == *pcbRead);
+
+  /*
+   * Advance the pointer for the number of positions read.
+   */
+  This->currentPosition.s.LowPart += *pcbRead;
+  
+  /*
+   * The function returns S_OK if the buffer was filled completely
+   * it returns S_FALSE if the end of the stream is reached before the
+   * buffer is filled
+   */
+  if(*pcbRead == cb)
+    return S_OK;
+  
+  return S_FALSE;
+}
+        
+/***
+ * This method is part of the ISequentialStream interface.
+ *
+ * It writes a block of information to the stream at the current
+ * position. It then moves the current position at the end of the
+ * written block. If the stream is too small to fit the block,
+ * the stream is grown to fit.
+ *
+ * See the documentation of ISequentialStream for more info.
+ */
+HRESULT WINAPI StgStreamImpl_Write(
+	          IStream*     iface,
+		  const void*    pv,          /* [size_is][in] */ 
+		  ULONG          cb,          /* [in] */          
+		  ULONG*         pcbWritten)  /* [out] */         
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  ULARGE_INTEGER newSize;
+  ULONG bytesWritten = 0;
+
+  TRACE("(%p, %p, %ld, %p)\n",
+	iface, pv, cb, pcbWritten);
+ 
+  /*
+   * Do we have permission to write to this stream?
+   */
+  if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE))) {
+      return STG_E_ACCESSDENIED;
+  }
+
+  /*
+   * If the caller is not interested in the number of bytes written,
+   * we use another buffer to avoid "if" statements in the code.
+   */
+  if (pcbWritten == 0)
+    pcbWritten = &bytesWritten;
+  
+  /*
+   * Initialize the out parameter
+   */
+  *pcbWritten = 0;
+
+  if (cb == 0)
+  {
+    return S_OK;
+  }
+  else
+  {
+    newSize.s.HighPart = 0;
+    newSize.s.LowPart = This->currentPosition.s.LowPart + cb;
+  }
+  
+  /*
+   * Verify if we need to grow the stream
+   */
+  if (newSize.s.LowPart > This->streamSize.s.LowPart)
+  {
+    /* grow stream */
+    IStream_SetSize(iface, newSize);
+  }
+  
+  /*
+   * Depending on the type of chain that was opened when the stream was constructed,
+   * we delegate the work to the method that readwrites to the block chains.
+   */
+  if (This->smallBlockChain!=0)
+  {
+    SmallBlockChainStream_WriteAt(This->smallBlockChain,
+				  This->currentPosition,
+				  cb,
+				  pv,
+				  pcbWritten);
+    
+  }
+  else if (This->bigBlockChain!=0)
+  {
+    BlockChainStream_WriteAt(This->bigBlockChain,
+			     This->currentPosition,
+			     cb,
+			     pv,
+			     pcbWritten);
+  }
+  else
+    assert(FALSE);
+  
+  /*
+   * Advance the position pointer for the number of positions written.
+   */
+  This->currentPosition.s.LowPart += *pcbWritten;
+  
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * It will move the current stream pointer according to the parameters
+ * given.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI StgStreamImpl_Seek( 
+		  IStream*      iface,
+		  LARGE_INTEGER   dlibMove,         /* [in] */ 
+		  DWORD           dwOrigin,         /* [in] */ 
+		  ULARGE_INTEGER* plibNewPosition) /* [out] */
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  ULARGE_INTEGER newPosition;
+
+  TRACE("(%p, %ld, %ld, %p)\n",
+	iface, dlibMove.s.LowPart, dwOrigin, plibNewPosition);
+
+  /* 
+   * The caller is allowed to pass in NULL as the new position return value.
+   * If it happens, we assign it to a dynamic variable to avoid special cases
+   * in the code below.
+   */
+  if (plibNewPosition == 0)
+  {
+    plibNewPosition = &newPosition;
+  }
+
+  /*
+   * The file pointer is moved depending on the given "function"
+   * parameter.
+   */
+  switch (dwOrigin)
+  {
+    case STREAM_SEEK_SET:
+      plibNewPosition->s.HighPart = 0;
+      plibNewPosition->s.LowPart  = 0;
+      break;
+    case STREAM_SEEK_CUR:
+      *plibNewPosition = This->currentPosition;
+      break;
+    case STREAM_SEEK_END:
+      *plibNewPosition = This->streamSize;
+      break;
+    default:
+      return STG_E_INVALIDFUNCTION;
+  }
+#ifdef __WIN32OS2__
+  /*
+   * do some multiword arithmetic:
+   *    treat HighPart as a signed value
+   *    treat LowPart as unsigned
+   *  NOTE: this stuff is two's complement specific!
+   */
+  if (dlibMove.s.HighPart < 0) { /* dlibMove is < 0 */
+      /* calculate the absolute value of dlibMove ... */
+      dlibMove.s.HighPart = -dlibMove.s.HighPart;
+      dlibMove.s.LowPart ^= -1;
+      /* ... and subtract with carry */
+      if (dlibMove.s.LowPart > plibNewPosition->s.LowPart) {
+	  /* carry needed, This accounts for any underflows at [1]*/
+	  plibNewPosition->s.HighPart -= 1; 
+      }
+      plibNewPosition->s.LowPart -= dlibMove.s.LowPart; /* [1] */
+      plibNewPosition->s.HighPart -= dlibMove.s.HighPart; 
+  } else {
+      /* add directly */
+      int initialLowPart = plibNewPosition->s.LowPart;
+      plibNewPosition->s.LowPart += dlibMove.s.LowPart;
+      if((plibNewPosition->s.LowPart < initialLowPart) ||
+	 (plibNewPosition->s.LowPart < dlibMove.s.LowPart)) {
+	  /* LowPart has rolled over => add the carry digit to HighPart */
+	  plibNewPosition->s.HighPart++;
+      }
+      plibNewPosition->s.HighPart += dlibMove.s.HighPart; 
+  }
+  /*
+   * Check if we end-up before the beginning of the file. That should 
+   * trigger an error.
+   */
+  if (plibNewPosition->s.HighPart < 0) {
+      return STG_E_INVALIDPOINTER;
+  }
+
+    /*
+   * We currently don't support files with offsets of >32 bits.  
+   * Note that we have checked for a negative offset already
+     */
+  assert(plibNewPosition->s.HighPart <= 0);
+
+#else
+  plibNewPosition->QuadPart = RtlLargeIntegerAdd( plibNewPosition->QuadPart, dlibMove.QuadPart );
+#endif
+
+  /*
+   * tell the caller what we calculated
+   */
+  This->currentPosition = *plibNewPosition;
+ 
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * It will change the size of a stream.
+ *
+ * TODO: Switch from small blocks to big blocks and vice versa.
+ *
+ * See the documentation of IStream for more info.
+ */
+HRESULT WINAPI StgStreamImpl_SetSize( 
+				     IStream*      iface,
+				     ULARGE_INTEGER  libNewSize)   /* [in] */ 
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  StgProperty    curProperty;
+  BOOL         Success;
+
+  TRACE("(%p, %ld)\n", iface, libNewSize.s.LowPart);
+
+  /*
+   * As documented.
+   */
+  if (libNewSize.s.HighPart != 0)
+    return STG_E_INVALIDFUNCTION;
+
+  /*
+   * Do we have permission?
+   */
+  if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
+    return STG_E_ACCESSDENIED;
+
+  if (This->streamSize.s.LowPart == libNewSize.s.LowPart)
+    return S_OK;
+
+  /*
+   * This will happen if we're creating a stream
+   */
+  if ((This->smallBlockChain == 0) && (This->bigBlockChain == 0))
+  {
+    if (libNewSize.s.LowPart < LIMIT_TO_USE_SMALL_BLOCK)
+    {
+      This->smallBlockChain = SmallBlockChainStream_Construct(
+                                    This->parentStorage->ancestorStorage,
+                                    This->ownerProperty);
+    }
+    else
+    {
+      This->bigBlockChain = BlockChainStream_Construct(
+                                This->parentStorage->ancestorStorage,
+                                NULL,
+                                This->ownerProperty);
+    }
+  }
+
+  /*
+   * Read this stream's property to see if it's small blocks or big blocks
+   */
+  Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
+                                       This->ownerProperty,
+                                       &curProperty); 
+  /*
+   * Determine if we have to switch from small to big blocks or vice versa
+   */  
+  if ( (This->smallBlockChain!=0) && 
+       (curProperty.size.s.LowPart < LIMIT_TO_USE_SMALL_BLOCK) )
+  {
+    if (libNewSize.s.LowPart >= LIMIT_TO_USE_SMALL_BLOCK)
+    {
+      /*
+       * Transform the small block chain into a big block chain
+       */
+      This->bigBlockChain = Storage32Impl_SmallBlocksToBigBlocks(
+                                This->parentStorage->ancestorStorage,
+                                &This->smallBlockChain);
+    }
+  }
+
+  if (This->smallBlockChain!=0)
+  {
+    Success = SmallBlockChainStream_SetSize(This->smallBlockChain, libNewSize);
+  }
+  else
+  {
+    Success = BlockChainStream_SetSize(This->bigBlockChain, libNewSize);
+  }
+
+  /*
+   * Write to the property the new information about this stream
+   */
+  Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
+                                       This->ownerProperty,
+                                       &curProperty);
+
+  curProperty.size.s.HighPart = libNewSize.s.HighPart;
+  curProperty.size.s.LowPart = libNewSize.s.LowPart;
+  
+  if (Success)
+  {
+    StorageImpl_WriteProperty(This->parentStorage->ancestorStorage,
+				This->ownerProperty,
+				&curProperty);
+  }
+  
+  This->streamSize = libNewSize;
+  
+  return S_OK;
+}
+        
+/***
+ * This method is part of the IStream interface.
+ *
+ * It will copy the 'cb' Bytes to 'pstm' IStream.
+ *
+ * See the documentation of IStream for more info.
+ */
+HRESULT WINAPI StgStreamImpl_CopyTo( 
+				    IStream*      iface,
+				    IStream*      pstm,         /* [unique][in] */ 
+				    ULARGE_INTEGER  cb,           /* [in] */         
+				    ULARGE_INTEGER* pcbRead,      /* [out] */        
+				    ULARGE_INTEGER* pcbWritten)   /* [out] */        
+{
+  HRESULT        hr = S_OK;
+  BYTE           tmpBuffer[128];
+  ULONG          bytesRead, bytesWritten, copySize;
+  ULARGE_INTEGER totalBytesRead;
+  ULARGE_INTEGER totalBytesWritten;
+
+  TRACE("(%p, %p, %ld, %p, %p)\n", 
+	iface, pstm, cb.s.LowPart, pcbRead, pcbWritten);
+
+  /*
+   * Sanity check
+   */
+  if ( pstm == 0 )
+    return STG_E_INVALIDPOINTER;
+
+  totalBytesRead.s.LowPart = totalBytesRead.s.HighPart = 0;
+  totalBytesWritten.s.LowPart = totalBytesWritten.s.HighPart = 0;
+
+  /*
+   * use stack to store data temporarly
+   * there is surely more performant way of doing it, for now this basic
+   * implementation will do the job
+   */
+  while ( cb.s.LowPart > 0 )
+  {
+    if ( cb.s.LowPart >= 128 )
+      copySize = 128;
+    else
+      copySize = cb.s.LowPart;
+    
+    IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
+
+    totalBytesRead.s.LowPart += bytesRead;
+    
+    IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
+
+    totalBytesWritten.s.LowPart += bytesWritten;
+
+    /*
+     * Check that read & write operations were succesfull
+     */
+    if (bytesRead != bytesWritten)
+    {
+      hr = STG_E_MEDIUMFULL;
+      break;
+    }
+    
+    if (bytesRead!=copySize)
+      cb.s.LowPart = 0;
+    else
+      cb.s.LowPart -= bytesRead;
+  }
+
+  /*
+   * Update number of bytes read and written
+   */
+  if (pcbRead)
+  {
+    pcbRead->s.LowPart = totalBytesRead.s.LowPart;
+    pcbRead->s.HighPart = totalBytesRead.s.HighPart;
+  }
+
+  if (pcbWritten)
+  {
+    pcbWritten->s.LowPart = totalBytesWritten.s.LowPart;
+    pcbWritten->s.HighPart = totalBytesWritten.s.HighPart;
+  }
+  return hr;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * For streams contained in structured storages, this method
+ * does nothing. This is what the documentation tells us.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI StgStreamImpl_Commit( 
+		  IStream*      iface,
+		  DWORD           grfCommitFlags)  /* [in] */ 
+{
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * For streams contained in structured storages, this method
+ * does nothing. This is what the documentation tells us.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI StgStreamImpl_Revert( 
+		  IStream* iface)
+{
+  return S_OK;
+}
+
+HRESULT WINAPI StgStreamImpl_LockRegion( 
+					IStream*     iface,
+					ULARGE_INTEGER libOffset,   /* [in] */ 
+					ULARGE_INTEGER cb,          /* [in] */ 
+					DWORD          dwLockType)  /* [in] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+HRESULT WINAPI StgStreamImpl_UnlockRegion( 
+					  IStream*     iface,
+					  ULARGE_INTEGER libOffset,   /* [in] */ 
+					  ULARGE_INTEGER cb,          /* [in] */ 
+					  DWORD          dwLockType)  /* [in] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * This method returns information about the current
+ * stream.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI StgStreamImpl_Stat( 
+		  IStream*     iface,
+		  STATSTG*       pstatstg,     /* [out] */
+		  DWORD          grfStatFlag)  /* [in] */ 
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  StgProperty    curProperty;
+  BOOL         readSucessful;
+  
+  /*
+   * Read the information from the property.
+   */
+  readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
+					     This->ownerProperty,
+					     &curProperty);
+  
+  if (readSucessful)
+  {
+    StorageUtl_CopyPropertyToSTATSTG(pstatstg, 
+				     &curProperty, 
+				     grfStatFlag);
+
+    pstatstg->grfMode = This->grfMode;
+    
+    return S_OK;
+  }
+  
+  return E_FAIL;
+}
+        
+HRESULT WINAPI StgStreamImpl_Clone( 
+				   IStream*     iface,
+				   IStream**    ppstm) /* [out] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
Index: trunk/src/ole32/stg_stream.cpp
===================================================================
--- trunk/src/ole32/stg_stream.cpp	(revision 5024)
+++ 	(revision )
@@ -1,885 +1,0 @@
-/* $Id: stg_stream.cpp,v 1.2 2000-03-19 15:33:07 davidr Exp $ */
-/* 
- * Compound Storage (32 bit version)
- * Stream implementation
- *
- * 20/9/99
- * 
- * Copyright 1999 David J. Raison
- * 
- * Direct port of Wine Implementation
- *
- * This file contains the implementation of the stream interface
- * for streams contained in a compound storage.
- * 
- * TODO:
- * - Support for a transacted mode
- *
- * Copyright 1999 Francis Beaudet
- * Copyright 1999 Thuy Nguyen
- */
-
-#include "ole32.h"
-#include "heapstring.h"
-#include "debugtools.h"
-#include "storage.h"
-
-#include <assert.h>
-
-DEFAULT_DEBUG_CHANNEL(storage)
-
-
-/*
- * Virtual function table for the StgStreamImpl class.
- */
-static ICOM_VTABLE(IStream) StgStreamImpl_Vtbl =
-{
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
-    StgStreamImpl_QueryInterface,
-    StgStreamImpl_AddRef,
-    StgStreamImpl_Release,
-    StgStreamImpl_Read,
-    StgStreamImpl_Write,
-    StgStreamImpl_Seek,
-    StgStreamImpl_SetSize,
-    StgStreamImpl_CopyTo,
-    StgStreamImpl_Commit,
-    StgStreamImpl_Revert,
-    StgStreamImpl_LockRegion,
-    StgStreamImpl_UnlockRegion,
-    StgStreamImpl_Stat,
-    StgStreamImpl_Clone
-};
-
-/******************************************************************************
-** StgStreamImpl implementation
-*/
-
-/***
- * This is the constructor for the StgStreamImpl class.
- *
- * Params:
- *    parentStorage - Pointer to the storage that contains the stream to open
- *    ownerProperty - Index of the property that points to this stream.
- */
-StgStreamImpl* StgStreamImpl_Construct(
-		StorageBaseImpl* parentStorage,
-		DWORD            grfMode,
-		ULONG              ownerProperty)
-{
-  StgStreamImpl* newStream;
-
-  newStream = (StgStreamImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl));
-  
-  if (newStream!=0)
-  {
-    /*
-     * Set-up the virtual function table and reference count.
-     */
-    ICOM_VTBL(newStream) = &StgStreamImpl_Vtbl;
-    newStream->ref    = 0;
-    
-    /*
-     * We want to nail-down the reference to the storage in case the
-     * stream out-lives the storage in the client application.
-     */
-    newStream->parentStorage = parentStorage;
-    IStorage_AddRef((IStorage*)newStream->parentStorage);
-    
-    newStream->grfMode = grfMode;    
-    newStream->ownerProperty = ownerProperty;
-    
-    /*
-     * Start the stream at the begining.
-     */
-    newStream->currentPosition.HighPart = 0;
-    newStream->currentPosition.LowPart = 0;
-    
-    /*
-     * Initialize the rest of the data.
-     */
-    newStream->streamSize.HighPart = 0;
-    newStream->streamSize.LowPart  = 0;
-    newStream->bigBlockChain       = 0;
-    newStream->smallBlockChain     = 0;
-    
-    /*
-     * Read the size from the property and determine if the blocks forming
-     * this stream are large or small.
-     */
-    StgStreamImpl_OpenBlockChain(newStream);
-  }
-  
-  return newStream;
-}
-
-/***
- * This is the destructor of the StgStreamImpl class.
- *
- * This method will clean-up all the resources used-up by the given StgStreamImpl 
- * class. The pointer passed-in to this function will be freed and will not
- * be valid anymore.
- */
-void StgStreamImpl_Destroy(StgStreamImpl* This)
-{
-  TRACE("(%p)\n", This);
-
-  /*
-   * Release the reference we are holding on the parent storage.
-   */
-  IStorage_Release((IStorage*)This->parentStorage);
-  This->parentStorage = 0;
-
-  /*
-   * Make sure we clean-up the block chain stream objects that we were using.
-   */
-  if (This->bigBlockChain != 0)
-  {
-    BlockChainStream_Destroy(This->bigBlockChain);
-    This->bigBlockChain = 0;
-  }
-
-  if (This->smallBlockChain != 0)
-  {
-    SmallBlockChainStream_Destroy(This->smallBlockChain);
-    This->smallBlockChain = 0;
-  }
-
-  /*
-   * Finally, free the memory used-up by the class.
-   */
-  HeapFree(GetProcessHeap(), 0, This);  
-}
-
-/***
- * This implements the IUnknown method QueryInterface for this
- * class
- */
-HRESULT WINAPI StgStreamImpl_QueryInterface(
-		  IStream*     iface,
-		  REFIID         riid,	      /* [in] */          
-		  void**         ppvObject)   /* [iid_is][out] */ 
-{
-  StgStreamImpl* const This=(StgStreamImpl*)iface;
-
-  /*
-   * Perform a sanity check on the parameters.
-   */
-  if (ppvObject==0)
-    return E_INVALIDARG;
-  
-  /*
-   * Initialize the return parameter.
-   */
-  *ppvObject = 0;
-  
-  /*
-   * Compare the riid with the interface IDs implemented by this object.
-   */
-  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
-  {
-    *ppvObject = (IStream*)This;
-  }
-  else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0) 
-  {
-    *ppvObject = (IStream*)This;
-  }
-  
-  /*
-   * 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
-   */
-  StgStreamImpl_AddRef(iface);
-  
-  return S_OK;;
-}
-
-/***
- * This implements the IUnknown method AddRef for this
- * class
- */
-ULONG WINAPI StgStreamImpl_AddRef(
-		IStream* iface)
-{
-  StgStreamImpl* const This=(StgStreamImpl*)iface;
-
-  This->ref++;
-  
-  return This->ref;
-}
-
-/***
- * This implements the IUnknown method Release for this
- * class
- */
-ULONG WINAPI StgStreamImpl_Release(
-		IStream* iface)
-{
-  StgStreamImpl* const This=(StgStreamImpl*)iface;
-
-  ULONG newRef;
-  
-  This->ref--;
-  
-  newRef = This->ref;
-  
-  /*
-   * If the reference count goes down to 0, perform suicide.
-   */
-  if (newRef==0)
-  {
-    StgStreamImpl_Destroy(This);
-  }
-  
-  return newRef;
-}
-
-/***
- * This method will open the block chain pointed by the property
- * that describes the stream.
- * If the stream's size is null, no chain is opened.
- */
-void StgStreamImpl_OpenBlockChain(
-        StgStreamImpl* This)
-{
-  StgProperty    curProperty;
-  BOOL         readSucessful;
-
-  /*
-   * Make sure no old object is staying behind.
-   */
-  if (This->smallBlockChain != 0)
-  {
-    SmallBlockChainStream_Destroy(This->smallBlockChain);
-    This->smallBlockChain = 0;
-  }
-
-  if (This->bigBlockChain != 0)
-  {
-    BlockChainStream_Destroy(This->bigBlockChain);
-    This->bigBlockChain = 0;
-  }
-
-  /*
-   * Read the information from the property.
-   */
-  readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
-					     This->ownerProperty,
-					     &curProperty);
-  
-  if (readSucessful)
-  {
-    This->streamSize = curProperty.size;
-    
-    /*
-     * This code supports only streams that are <32 bits in size.
-     */
-    assert(This->streamSize.HighPart == 0);
-    
-    if(curProperty.startingBlock == BLOCK_END_OF_CHAIN)
-    {
-      assert( (This->streamSize.HighPart == 0) && (This->streamSize.LowPart == 0) );
-    }
-    else
-    {
-      if ( (This->streamSize.HighPart == 0) &&
-	   (This->streamSize.LowPart < LIMIT_TO_USE_SMALL_BLOCK) )
-      {
-	This->smallBlockChain = SmallBlockChainStream_Construct(
-								This->parentStorage->ancestorStorage,	
-								This->ownerProperty);
-      }
-      else
-      {
-	This->bigBlockChain = BlockChainStream_Construct(
-							 This->parentStorage->ancestorStorage,
-							 NULL,
-							 This->ownerProperty);
-      }
-    }
-  }
-}
-
-/***
- * This method is part of the ISequentialStream interface.
- *
- * If reads a block of information from the stream at the current
- * position. It then moves the current position at the end of the
- * read block
- *
- * See the documentation of ISequentialStream for more info.
- */
-HRESULT WINAPI StgStreamImpl_Read( 
-		  IStream*     iface,
-		  void*          pv,        /* [length_is][size_is][out] */
-		  ULONG          cb,        /* [in] */                     
-		  ULONG*         pcbRead)   /* [out] */                    
-{
-  StgStreamImpl* const This=(StgStreamImpl*)iface;
-
-  ULONG bytesReadBuffer;
-  ULONG bytesToReadFromBuffer;
-
-  TRACE("(%p, %p, %ld, %p)\n",
-	iface, pv, cb, pcbRead);
-
-  /* 
-   * If the caller is not interested in the nubmer of bytes read,
-   * we use another buffer to avoid "if" statements in the code.
-   */
-  if (pcbRead==0)
-    pcbRead = &bytesReadBuffer;
-  
-  /*
-   * Using the known size of the stream, calculate the number of bytes
-   * to read from the block chain
-   */
-  bytesToReadFromBuffer = MIN( This->streamSize.LowPart - This->currentPosition.LowPart, cb);
-  
-  /*
-   * Depending on the type of chain that was opened when the stream was constructed,
-   * we delegate the work to the method that read the block chains.
-   */
-  if (This->smallBlockChain!=0)
-  {
-    SmallBlockChainStream_ReadAt(This->smallBlockChain,
-				 This->currentPosition,
-				 bytesToReadFromBuffer,
-				 pv,
-				 pcbRead);
-    
-  }
-  else if (This->bigBlockChain!=0)
-  {
-    BlockChainStream_ReadAt(This->bigBlockChain,
-			    This->currentPosition,
-			    bytesToReadFromBuffer,
-			    pv,
-			    pcbRead);
-  }
-  else
-  {
-    /*
-     * Small and big block chains are both NULL. This case will happen
-     * when a stream starts with BLOCK_END_OF_CHAIN and has size zero.
-     */
-
-    *pcbRead = 0;
-    return S_OK;
-  }
-
-  /*
-   * We should always be able to read the proper amount of data from the
-   * chain.
-   */
-  assert(bytesToReadFromBuffer == *pcbRead);
-
-  /*
-   * Advance the pointer for the number of positions read.
-   */
-  This->currentPosition.LowPart += *pcbRead;
-  
-  /*
-   * The function returns S_OK if the buffer was filled completely
-   * it returns S_FALSE if the end of the stream is reached before the
-   * buffer is filled
-   */
-  if(*pcbRead == cb)
-    return S_OK;
-  
-  return S_FALSE;
-}
-        
-/***
- * This method is part of the ISequentialStream interface.
- *
- * It writes a block of information to the stream at the current
- * position. It then moves the current position at the end of the
- * written block. If the stream is too small to fit the block,
- * the stream is grown to fit.
- *
- * See the documentation of ISequentialStream for more info.
- */
-HRESULT WINAPI StgStreamImpl_Write(
-	          IStream*     iface,
-		  const void*    pv,          /* [size_is][in] */ 
-		  ULONG          cb,          /* [in] */          
-		  ULONG*         pcbWritten)  /* [out] */         
-{
-  StgStreamImpl* const This=(StgStreamImpl*)iface;
-
-  ULARGE_INTEGER newSize;
-  ULONG bytesWritten = 0;
-
-  TRACE("(%p, %p, %ld, %p)\n",
-	iface, pv, cb, pcbWritten);
-  
-  /*
-   * If the caller is not interested in the number of bytes written,
-   * we use another buffer to avoid "if" statements in the code.
-   */
-  if (pcbWritten == 0)
-    pcbWritten = &bytesWritten;
-  
-  /*
-   * Initialize the out parameter
-   */
-  *pcbWritten = 0;
-
-  /*
-   * Do we have permission to write to this stream?
-   */
-  if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
-    return STG_E_ACCESSDENIED;
-
-  if (cb == 0)
-  {
-    return S_OK;
-  }
-  else
-  {
-    newSize.HighPart = 0;
-    newSize.LowPart = This->currentPosition.LowPart + cb;
-  }
-  
-  /*
-   * Verify if we need to grow the stream
-   */
-  if (newSize.LowPart > This->streamSize.LowPart)
-  {
-    /* grow stream */
-    IStream_SetSize(iface, newSize);
-  }
-  
-  /*
-   * Depending on the type of chain that was opened when the stream was constructed,
-   * we delegate the work to the method that readwrites to the block chains.
-   */
-  if (This->smallBlockChain!=0)
-  {
-    SmallBlockChainStream_WriteAt(This->smallBlockChain,
-				  This->currentPosition,
-				  cb,
-				  pv,
-				  pcbWritten);
-    
-  }
-  else if (This->bigBlockChain!=0)
-  {
-    BlockChainStream_WriteAt(This->bigBlockChain,
-			     This->currentPosition,
-			     cb,
-			     pv,
-			     pcbWritten);
-  }
-  else
-    assert(FALSE);
-  
-  /*
-   * Advance the position pointer for the number of positions written.
-   */
-  This->currentPosition.LowPart += *pcbWritten;
-  
-  return S_OK;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * It will move the current stream pointer according to the parameters
- * given.
- *
- * See the documentation of IStream for more info.
- */        
-HRESULT WINAPI StgStreamImpl_Seek( 
-		  IStream*      iface,
-		  LARGE_INTEGER   dlibMove,         /* [in] */ 
-		  DWORD           dwOrigin,         /* [in] */ 
-		  ULARGE_INTEGER* plibNewPosition) /* [out] */
-{
-  StgStreamImpl* const This=(StgStreamImpl*)iface;
-
-  ULARGE_INTEGER newPosition;
-
-  TRACE("(%p, %ld, %ld, %p)\n",
-	iface, dlibMove.LowPart, dwOrigin, plibNewPosition);
-
-  /* 
-   * The caller is allowed to pass in NULL as the new position return value.
-   * If it happens, we assign it to a dynamic variable to avoid special cases
-   * in the code below.
-   */
-  if (plibNewPosition == 0)
-  {
-    plibNewPosition = &newPosition;
-  }
-
-  /*
-   * The file pointer is moved depending on the given "function"
-   * parameter.
-   */
-  switch (dwOrigin)
-  {
-    case STREAM_SEEK_SET:
-      plibNewPosition->HighPart = 0;
-      plibNewPosition->LowPart  = 0;
-      break;
-    case STREAM_SEEK_CUR:
-      *plibNewPosition = This->currentPosition;
-      break;
-    case STREAM_SEEK_END:
-      *plibNewPosition = This->streamSize;
-      break;
-    default:
-      return STG_E_INVALIDFUNCTION;
-  }
-
-#if SIZEOF_LONG_LONG >= 8
-  plibNewPosition->QuadPart += dlibMove.QuadPart;
-#else
-  /*
-   * do some multiword arithmetic:
-   *    treat HighPart as a signed value
-   *    treat LowPart as unsigned
-   *  NOTE: this stuff is two's complement specific!
-   */
-  if (dlibMove.HighPart < 0) { /* dlibMove is < 0 */
-      /* calculate the absolute value of dlibMove ... */
-      dlibMove.HighPart = -dlibMove.HighPart;
-      dlibMove.LowPart ^= -1;
-      /* ... and subtract with carry */
-      if (dlibMove.LowPart > plibNewPosition->LowPart) {
-	  /* carry needed, This accounts for any underflows at [1]*/
-	  plibNewPosition->HighPart -= 1; 
-      }
-      plibNewPosition->LowPart -= dlibMove.LowPart; /* [1] */
-      plibNewPosition->HighPart -= dlibMove.HighPart; 
-  } else {
-      /* add directly */
-      int initialLowPart = plibNewPosition->LowPart;
-      plibNewPosition->LowPart += dlibMove.LowPart;
-      if((plibNewPosition->LowPart < initialLowPart) ||
-	 (plibNewPosition->LowPart < dlibMove.LowPart)) {
-	  /* LowPart has rolled over => add the carry digit to HighPart */
-	  plibNewPosition->HighPart++;
-      }
-      plibNewPosition->HighPart += dlibMove.HighPart; 
-  }
-  /*
-   * Check if we end-up before the beginning of the file. That should 
-   * trigger an error.
-   */
-  if (plibNewPosition->HighPart < 0) {
-      return STG_E_INVALIDPOINTER;
-  }
-
-    /*
-   * We currently don't support files with offsets of >32 bits.  
-   * Note that we have checked for a negative offset already
-     */
-  assert(plibNewPosition->HighPart <= 0);
-
-#endif
-
-  /*
-   * tell the caller what we calculated
-   */
-  This->currentPosition = *plibNewPosition;
- 
-  return S_OK;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * It will change the size of a stream.
- *
- * TODO: Switch from small blocks to big blocks and vice versa.
- *
- * See the documentation of IStream for more info.
- */
-HRESULT WINAPI StgStreamImpl_SetSize( 
-				     IStream*      iface,
-				     ULARGE_INTEGER  libNewSize)   /* [in] */ 
-{
-  StgStreamImpl* const This=(StgStreamImpl*)iface;
-
-  StgProperty    curProperty;
-  BOOL         Success;
-
-  TRACE("(%p, %ld)\n", iface, libNewSize.LowPart);
-
-  /*
-   * As documented.
-   */
-  if (libNewSize.HighPart != 0)
-    return STG_E_INVALIDFUNCTION;
-  
-  /*
-   * Do we have permission?
-   */
-  if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
-    return STG_E_ACCESSDENIED;
-
-  if (This->streamSize.LowPart == libNewSize.LowPart)
-    return S_OK;
-
-  /*
-   * This will happen if we're creating a stream
-   */
-  if ((This->smallBlockChain == 0) && (This->bigBlockChain == 0))
-  {
-    if (libNewSize.LowPart < LIMIT_TO_USE_SMALL_BLOCK)
-    {
-      This->smallBlockChain = SmallBlockChainStream_Construct(
-                                    This->parentStorage->ancestorStorage,
-                                    This->ownerProperty);
-    }
-    else
-    {
-      This->bigBlockChain = BlockChainStream_Construct(
-                                This->parentStorage->ancestorStorage,
-                                NULL,
-                                This->ownerProperty);
-    }
-  }
-
-  /*
-   * Read this stream's property to see if it's small blocks or big blocks
-   */
-  Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
-                                       This->ownerProperty,
-                                       &curProperty); 
-  /*
-   * Determine if we have to switch from small to big blocks or vice versa
-   */  
-  if ( (This->smallBlockChain!=0) && 
-       (curProperty.size.LowPart < LIMIT_TO_USE_SMALL_BLOCK) )
-  {
-    if (libNewSize.LowPart >= LIMIT_TO_USE_SMALL_BLOCK)
-    {
-      /*
-       * Transform the small block chain into a big block chain
-       */
-      This->bigBlockChain = Storage32Impl_SmallBlocksToBigBlocks(
-                                This->parentStorage->ancestorStorage,
-                                &This->smallBlockChain);
-    }
-  }
-
-  if (This->smallBlockChain!=0)
-  {
-    Success = SmallBlockChainStream_SetSize(This->smallBlockChain, libNewSize);
-  }
-  else
-  {
-    Success = BlockChainStream_SetSize(This->bigBlockChain, libNewSize);
-  }
-
-  /*
-   * Write to the property the new information about this stream
-   */
-  Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
-                                       This->ownerProperty,
-                                       &curProperty);
-
-  curProperty.size.HighPart = libNewSize.HighPart;
-  curProperty.size.LowPart = libNewSize.LowPart;
-  
-  if (Success)
-  {
-    StorageImpl_WriteProperty(This->parentStorage->ancestorStorage,
-				This->ownerProperty,
-				&curProperty);
-  }
-  
-  This->streamSize = libNewSize;
-  
-  return S_OK;
-}
-        
-/***
- * This method is part of the IStream interface.
- *
- * It will copy the 'cb' Bytes to 'pstm' IStream.
- *
- * See the documentation of IStream for more info.
- */
-HRESULT WINAPI StgStreamImpl_CopyTo( 
-				    IStream*      iface,
-				    IStream*      pstm,         /* [unique][in] */ 
-				    ULARGE_INTEGER  cb,           /* [in] */         
-				    ULARGE_INTEGER* pcbRead,      /* [out] */        
-				    ULARGE_INTEGER* pcbWritten)   /* [out] */        
-{
-  HRESULT        hr = S_OK;
-  BYTE           tmpBuffer[128];
-  ULONG          bytesRead, bytesWritten, copySize;
-  ULARGE_INTEGER totalBytesRead;
-  ULARGE_INTEGER totalBytesWritten;
-
-  TRACE("(%p, %p, %ld, %p, %p)\n", 
-	iface, pstm, cb.LowPart, pcbRead, pcbWritten);
-
-  /*
-   * Sanity check
-   */
-  if ( pstm == 0 )
-    return STG_E_INVALIDPOINTER;
-
-  totalBytesRead.LowPart = totalBytesRead.HighPart = 0;
-  totalBytesWritten.LowPart = totalBytesWritten.HighPart = 0;
-
-  /*
-   * use stack to store data temporarly
-   * there is surely more performant way of doing it, for now this basic
-   * implementation will do the job
-   */
-  while ( cb.LowPart > 0 )
-  {
-    if ( cb.LowPart >= 128 )
-      copySize = 128;
-    else
-      copySize = cb.LowPart;
-    
-    IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
-
-    totalBytesRead.LowPart += bytesRead;
-    
-    IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
-
-    totalBytesWritten.LowPart += bytesWritten;
-
-    /*
-     * Check that read & write operations were succesfull
-     */
-    if (bytesRead != bytesWritten)
-    {
-      hr = STG_E_MEDIUMFULL;
-      break;
-    }
-    
-    if (bytesRead!=copySize)
-      cb.LowPart = 0;
-    else
-      cb.LowPart -= bytesRead;
-  }
-
-  /*
-   * Update number of bytes read and written
-   */
-  if (pcbRead)
-  {
-    pcbRead->LowPart = totalBytesRead.LowPart;
-    pcbRead->HighPart = totalBytesRead.HighPart;
-  }
-
-  if (pcbWritten)
-  {
-    pcbWritten->LowPart = totalBytesWritten.LowPart;
-    pcbWritten->HighPart = totalBytesWritten.HighPart;
-  }
-  return hr;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * For streams contained in structured storages, this method
- * does nothing. This is what the documentation tells us.
- *
- * See the documentation of IStream for more info.
- */        
-HRESULT WINAPI StgStreamImpl_Commit( 
-		  IStream*      iface,
-		  DWORD           grfCommitFlags)  /* [in] */ 
-{
-  return S_OK;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * For streams contained in structured storages, this method
- * does nothing. This is what the documentation tells us.
- *
- * See the documentation of IStream for more info.
- */        
-HRESULT WINAPI StgStreamImpl_Revert( 
-		  IStream* iface)
-{
-  return S_OK;
-}
-
-HRESULT WINAPI StgStreamImpl_LockRegion( 
-					IStream*     iface,
-					ULARGE_INTEGER libOffset,   /* [in] */ 
-					ULARGE_INTEGER cb,          /* [in] */ 
-					DWORD          dwLockType)  /* [in] */ 
-{
-  FIXME("not implemented!\n");
-  return E_NOTIMPL;
-}
-
-HRESULT WINAPI StgStreamImpl_UnlockRegion( 
-					  IStream*     iface,
-					  ULARGE_INTEGER libOffset,   /* [in] */ 
-					  ULARGE_INTEGER cb,          /* [in] */ 
-					  DWORD          dwLockType)  /* [in] */ 
-{
-  FIXME("not implemented!\n");
-  return E_NOTIMPL;
-}
-
-/***
- * This method is part of the IStream interface.
- *
- * This method returns information about the current
- * stream.
- *
- * See the documentation of IStream for more info.
- */        
-HRESULT WINAPI StgStreamImpl_Stat( 
-		  IStream*     iface,
-		  STATSTG*       pstatstg,     /* [out] */
-		  DWORD          grfStatFlag)  /* [in] */ 
-{
-  StgStreamImpl* const This=(StgStreamImpl*)iface;
-
-  StgProperty    curProperty;
-  BOOL         readSucessful;
-  
-  /*
-   * Read the information from the property.
-   */
-  readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
-					     This->ownerProperty,
-					     &curProperty);
-  
-  if (readSucessful)
-  {
-    StorageUtl_CopyPropertyToSTATSTG(pstatstg, 
-				     &curProperty, 
-				     grfStatFlag);
-    
-    pstatstg->grfMode = This->grfMode;
-
-    return S_OK;
-  }
-  
-  return E_FAIL;
-}
-        
-HRESULT WINAPI StgStreamImpl_Clone( 
-				   IStream*     iface,
-				   IStream**    ppstm) /* [out] */ 
-{
-  FIXME("not implemented!\n");
-  return E_NOTIMPL;
-}
Index: trunk/src/ole32/storage.cpp
===================================================================
--- trunk/src/ole32/storage.cpp	(revision 5024)
+++ 	(revision )
@@ -1,7546 +1,0 @@
-/* $Id: storage.cpp,v 1.2 2000-03-19 15:33:08 davidr Exp $ */
-/* 
- * Compound Storage functions.
- * 
- * 20/9/99
- * 
- * Copyright 1999 David J. Raison
- * 
- * Direct port of Wine Implementation
- *   Copyright 1999 Francis Beaudet
- *   Copyright 1999 Sylvain St-Germain
- *   Copyright 1999 Thuy Nguyen
- *   Copyright 1998 Marcus Meissner
- *
- * Implemented using the documentation of the LAOLA project at
- * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
- * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
- *
- */
-
-#include "ole32.h"
-#include "heapstring.h"
-#include "debugtools.h"
-#include <assert.h>
-
-#include "storage.h"
-
-#include "winnls.h"
-#include "winreg.h"
-#include "wine/wingdi16.h"
-
-DEFAULT_DEBUG_CHANNEL(storage)
-
-#define FILE_BEGIN 0
-
-
-/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
-#define OLESTREAM_ID 0x501
-#define OLESTREAM_MAX_STR_LEN 255
-
-#define OLECONVERT_NUM_OLE10STREAMS 2
-
-#define OLECONVERT_LINK_TYPE              1L
-#define OLECONVERT_EMBEDDED_TYPE          2L
-#define OLECONVERT_PRESENTATION_DATA_TYPE 5L
-
-static const char rootPropertyName[] = "Root Entry";
-
-
-/* OLESTREAM memory structure to use for Get and Put Routines */
-/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
-typedef struct 
-{
-    DWORD dwOleID;
-    DWORD dwObjectTypeID;
-    DWORD dwOleTypeNameLength;
-    CHAR  strOleTypeName[OLESTREAM_MAX_STR_LEN];
-    DWORD dwLinkFileNameLength;
-    BYTE *strLinkFileName;
-    DWORD dwLinkExtraInfoLength;
-    BYTE *pLinkExtraInfo;
-    DWORD dwMetaFileWidth;
-    DWORD dwMetaFileHeight;
-    DWORD dwDataLength;
-    BYTE *pData;
-}OLECONVERT_OLESTREAM_DATA;
-
-/* CompObj Stream structure */
-/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
-typedef struct
-{
-    BYTE byUnknown1[12];
-    CLSID clsid;
-    DWORD dwCLSIDNameLength;
-    CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
-    DWORD dwOleTypeNameLength;
-    CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
-    DWORD dwProgIDNameLength;
-    CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
-    BYTE byUnknown2[16];
-}OLECONVERT_ISTORAGE_COMPOBJ;
-
-
-/* Ole Presention Stream structure */
-/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
-typedef struct
-{
-    BYTE byUnknown1[28];
-    DWORD dwExtentX;
-    DWORD dwExtentY;
-    DWORD dwSize;  
-    BYTE *pData;
-}OLECONVERT_ISTORAGE_OLEPRES;
-
-
-/* Ole Stream Structure */
-/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
-typedef struct
-{
-    DWORD dwOLEHEADER_ID;
-    DWORD dwUnknown1;
-    DWORD dwUnknown2;
-    DWORD dwUnknown3;
-    DWORD dwUnknown4; /*Only used when using a Moniker is present in the /001Ole Stream*/
-    DWORD dwUnknown5; /*Only used when using a Moniker is present in the /001Ole stream*/
-    DWORD dwObjectCLSIDOffset;
-    CLSID clsidMonikerTypeID;
-    /*Save info for clsidMonikerTypeID (eg. FileMoniker, ItemMoniker, or CompositeMoniker) */
-    DWORD dwUnknown6;
-    CLSID clsidObject;
-    BYTE dwUnknown7[32];
-}OLECONVERT_ISTORAGE_OLE;
-
-
-
-
-/***********************************************************************
- * Forward declaration of internal functions used by the method DestroyElement
- */
-static HRESULT deleteStorageProperty(
-  StorageImpl *parentStorage,
-  ULONG        foundPropertyIndexToDelete,
-  StgProperty  propertyToDelete);
-
-static HRESULT deleteStreamProperty(
-  StorageImpl *parentStorage,
-  ULONG         foundPropertyIndexToDelete,
-  StgProperty   propertyToDelete);
-
-static HRESULT findPlaceholder(
-  StorageImpl *storage,
-  ULONG         propertyIndexToStore,
-  ULONG         storagePropertyIndex,
-  INT         typeOfRelation);
-
-static HRESULT adjustPropertyChain( 
-  StorageImpl *This,
-  StgProperty   propertyToDelete,
-  StgProperty   parentProperty,
-  ULONG         parentPropertyId,
-  INT         typeOfRelation);
-
-/***********************************************************************
- * Declaration of the functions used to manipulate StgProperty
- */
-
-static ULONG getFreeProperty(
-  StorageImpl *storage);
-
-static void updatePropertyChain(
-  StorageImpl *storage,
-  ULONG       newPropertyIndex,
-  StgProperty newProperty);
-
-static LONG propertyNameCmp(
-  OLECHAR *newProperty,
-  OLECHAR *currentProperty);
-
-
-/***********************************************************************
- * Declaration of miscellaneous functions...
- */
-static HRESULT validateSTGM(DWORD stgmValue); 
-
-static DWORD GetShareModeFromSTGM(DWORD stgm);
-static DWORD GetAccessModeFromSTGM(DWORD stgm);
-static DWORD GetCreationModeFromSTGM(DWORD stgm);
-
-/*
- * Virtual function table for the IStorage32Impl class.
- */
-static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
-{
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
-    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,
-    StorageBaseImpl_Stat
-};
-
-/*
- * Virtual function table for the Storage32InternalImpl class.
- */
-static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
-  {
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
-    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.
- */
-static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
-{
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
-    IEnumSTATSTGImpl_QueryInterface,
-    IEnumSTATSTGImpl_AddRef,
-    IEnumSTATSTGImpl_Release,
-    IEnumSTATSTGImpl_Next,
-    IEnumSTATSTGImpl_Skip,
-    IEnumSTATSTGImpl_Reset,
-    IEnumSTATSTGImpl_Clone
-};
-
-
-
-
-
-/************************************************************************
-** Storage32BaseImpl implementatiion
-*/
-
-/************************************************************************
- * Storage32BaseImpl_QueryInterface (IUnknown)
- *
- * This method implements the common QueryInterface for all IStorage32
- * implementations contained in this file.
- * 
- * See Windows documentation for more details on IUnknown methods.
- */
-HRESULT WINAPI StorageBaseImpl_QueryInterface(
-  IStorage*        iface,
-  REFIID             riid,
-  void**             ppvObject)
-{
-  ICOM_THIS(StorageBaseImpl,iface);
-  /*
-   * Perform a sanity check on the parameters.
-   */
-  if ( (This==0) || (ppvObject==0) )
-    return E_INVALIDARG;
-  
-  /*
-   * Initialize the return parameter.
-   */
-  *ppvObject = 0;
-  
-  /*
-   * Compare the riid with the interface IDs implemented by this object.
-   */
-  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
-  {
-    *ppvObject = (IStorage*)This;
-  }
-  else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0) 
-  {
-    *ppvObject = (IStorage*)This;
-  }
-  
-  /*
-   * 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
-   */
-  StorageBaseImpl_AddRef(iface);
-
-  return S_OK;
-}
-        
-/************************************************************************
- * Storage32BaseImpl_AddRef (IUnknown)
- *
- * This method implements the common AddRef for all IStorage32
- * implementations contained in this file.
- * 
- * See Windows documentation for more details on IUnknown methods.
- */
-ULONG WINAPI StorageBaseImpl_AddRef( 
-            IStorage* iface)
-{
-  ICOM_THIS(StorageBaseImpl,iface);
-  This->ref++;
-
-  return This->ref;
-}
-        
-/************************************************************************
- * Storage32BaseImpl_Release (IUnknown)
- *
- * This method implements the common Release for all IStorage32
- * implementations contained in this file.
- * 
- * See Windows documentation for more details on IUnknown methods.
- */
-ULONG WINAPI StorageBaseImpl_Release( 
-      IStorage* iface)
-{
-  ICOM_THIS(StorageBaseImpl,iface);
-  /*
-   * Decrease the reference count on this object.
-   */
-  This->ref--;
-
-  /*
-   * If the reference count goes down to 0, perform suicide.
-   */
-  if (This->ref==0)
-  {
-    /*
-     * Since we are using a system of base-classes, we want to call the 
-     * destructor of the appropriate derived class. To do this, we are 
-     * using virtual functions to implement the destructor.
-     */
-    This->v_destructor(This);
-
-    return 0;
-  }
-  
-  return This->ref;
-}
-
-/************************************************************************
- * Storage32BaseImpl_OpenStream (IStorage)
- *
- * This method will open the specified stream object from the current storage.
- *
- * See Windows documentation for more details on IStorage methods.
- */
-HRESULT WINAPI StorageBaseImpl_OpenStream( 
-  IStorage*        iface,
-  const OLECHAR*   pwcsName,  /* [string][in] */
-  void*            reserved1, /* [unique][in] */
-  DWORD            grfMode,   /* [in]  */        
-  DWORD            reserved2, /* [in]  */        
-  IStream**        ppstm)     /* [out] */       
-{
-  ICOM_THIS(StorageBaseImpl,iface);
-  IEnumSTATSTGImpl* propertyEnumeration;
-  StgStreamImpl*    newStream;
-  StgProperty       currentProperty;
-  ULONG             foundPropertyIndex;
-
-  TRACE("(%p, %s, %p, %lx, %ld, %p)\n", 
-	iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
-
-  /*
-   * Perform a sanity check on the parameters.
-   */
-  if ( (pwcsName==NULL) || (ppstm==0) )
-    return E_INVALIDARG;
-  
-  /*
-   * Initialize the out parameter
-   */
-  *ppstm = 0;
-  
-  /*
-   * Validate the STGM flags
-   */
-  if ( FAILED( validateSTGM(grfMode) ))
-    return STG_E_INVALIDFLAG;
-
-  /*
-   * As documented.
-   */
-  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
-        (grfMode & STGM_DELETEONRELEASE) ||
-        (grfMode & STGM_TRANSACTED) )
-    return STG_E_INVALIDFUNCTION;
-
-  /*
-   * Create a property enumeration to search the properties
-   */
-  propertyEnumeration = IEnumSTATSTGImpl_Construct(
-    This->ancestorStorage, 
-    This->rootPropertySetIndex);
-  
-  /*
-   * Search the enumeration for the property with the given name
-   */
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
-    propertyEnumeration,
-    pwcsName,
-    &currentProperty);
-  
-  /*
-   * Delete the property enumeration since we don't need it anymore
-   */
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
-  
-  /*
-   * If it was found, construct the stream object and return a pointer to it.
-   */
-  if ( (foundPropertyIndex!=PROPERTY_NULL) && 
-       (currentProperty.propertyType==PROPTYPE_STREAM) )
-  {
-    newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);
-    
-    if (newStream!=0)
-    {
-      *ppstm = (IStream*)newStream;
-
-      /*
-       * Since we are returning a pointer to the interface, we have to 
-       * nail down the reference.
-       */
-      StgStreamImpl_AddRef(*ppstm);
-      
-      return S_OK;
-    }
-    
-    return E_OUTOFMEMORY;
-  }
-  
-  return STG_E_FILENOTFOUND;
-}
-
-/************************************************************************
- * Storage32BaseImpl_OpenStorage (IStorage)
- *
- * This method will open a new storage object from the current storage.
- * 
- * See Windows documentation for more details on IStorage methods.
- */        
-HRESULT WINAPI StorageBaseImpl_OpenStorage( 
-  IStorage*        iface,
-  const OLECHAR*   pwcsName,      /* [string][unique][in] */ 
-  IStorage*        pstgPriority,  /* [unique][in] */         
-  DWORD            grfMode,       /* [in] */                 
-  SNB              snbExclude,    /* [unique][in] */         
-  DWORD            reserved,      /* [in] */                 
-  IStorage**       ppstg)         /* [out] */                        
-{
-  ICOM_THIS(StorageBaseImpl,iface);
-  StorageInternalImpl* newStorage;
-  IEnumSTATSTGImpl*      propertyEnumeration;
-  StgProperty            currentProperty;
-  ULONG                  foundPropertyIndex;
-
-  TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n", 
-	iface, debugstr_w(pwcsName), pstgPriority, 
-	grfMode, snbExclude, reserved, ppstg);
-  
-  /*
-   * Perform a sanity check on the parameters.
-   */
-  if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
-    return E_INVALIDARG;
-  
-  /*
-   * Validate the STGM flags
-   */
-  if ( FAILED( validateSTGM(grfMode) ))
-    return STG_E_INVALIDFLAG;
-
-  /*
-   * As documented.
-   */
-  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) || 
-        (grfMode & STGM_DELETEONRELEASE) ||
-        (grfMode & STGM_PRIORITY) )
-    return STG_E_INVALIDFUNCTION;
-
-  /*
-   * Initialize the out parameter
-   */
-  *ppstg = 0;
-  
-  /*
-   * Create a property enumeration to search the properties
-   */
-  propertyEnumeration = IEnumSTATSTGImpl_Construct(
-                          This->ancestorStorage, 
-                          This->rootPropertySetIndex);
-  
-  /*
-   * Search the enumeration for the property with the given name
-   */
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
-                         propertyEnumeration,
-                         pwcsName,
-                         &currentProperty);
-  
-  /*
-   * Delete the property enumeration since we don't need it anymore
-   */
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
-  
-  /*
-   * If it was found, construct the stream object and return a pointer to it.
-   */
-  if ( (foundPropertyIndex!=PROPERTY_NULL) && 
-       (currentProperty.propertyType==PROPTYPE_STORAGE) )
-  {
-    /*
-     * Construct a new Storage object
-     */
-    newStorage = StorageInternalImpl_Construct(
-                   This->ancestorStorage,
-                   foundPropertyIndex);
-    
-    if (newStorage != 0)
-    {
-      *ppstg = (IStorage*)newStorage;
-
-      /*
-       * Since we are returning a pointer to the interface, 
-       * we have to nail down the reference.
-       */
-      StorageBaseImpl_AddRef(*ppstg);
-      
-      return S_OK;
-    }
-    
-    return STG_E_INSUFFICIENTMEMORY;
-  }
-  
-  return STG_E_FILENOTFOUND;
-}
-
-/************************************************************************
- * Storage32BaseImpl_EnumElements (IStorage)
- *
- * This method will create an enumerator object that can be used to 
- * retrieve informatino about all the properties in the storage object.
- * 
- * See Windows documentation for more details on IStorage methods.
- */        
-HRESULT WINAPI StorageBaseImpl_EnumElements( 
-  IStorage*       iface,
-  DWORD           reserved1, /* [in] */                  
-  void*           reserved2, /* [size_is][unique][in] */ 
-  DWORD           reserved3, /* [in] */                  
-  IEnumSTATSTG**  ppenum)    /* [out] */                 
-{
-  ICOM_THIS(StorageBaseImpl,iface);
-  IEnumSTATSTGImpl* newEnum;
-
-  TRACE("(%p, %ld, %p, %ld, %p)\n", 
-	iface, reserved1, reserved2, reserved3, ppenum);
-
-  /*
-   * Perform a sanity check on the parameters.
-   */
-  if ( (This==0) || (ppenum==0))
-    return E_INVALIDARG;
-  
-  /*
-   * Construct the enumerator.
-   */
-  newEnum = IEnumSTATSTGImpl_Construct(
-              This->ancestorStorage,
-              This->rootPropertySetIndex);
-
-  if (newEnum!=0)
-  {
-    *ppenum = (IEnumSTATSTG*)newEnum;
-
-    /*
-     * Don't forget to nail down a reference to the new object before
-     * returning it.
-     */
-    IEnumSTATSTGImpl_AddRef(*ppenum);
-    
-    return S_OK;
-  }
-
-  return E_OUTOFMEMORY;
-}
-
-/************************************************************************
- * Storage32BaseImpl_Stat (IStorage)
- *
- * This method will retrieve information about this storage object.
- * 
- * See Windows documentation for more details on IStorage methods.
- */        
-HRESULT WINAPI StorageBaseImpl_Stat( 
-  IStorage*        iface,
-  STATSTG*         pstatstg,     /* [out] */ 
-  DWORD            grfStatFlag)  /* [in] */  
-{
-  ICOM_THIS(StorageBaseImpl,iface);
-  StgProperty    curProperty;
-  BOOL         readSucessful;
-
-  TRACE("(%p, %p, %lx)\n", 
-	iface, pstatstg, grfStatFlag);
-
-  /*
-   * Perform a sanity check on the parameters.
-   */
-  if ( (This==0) || (pstatstg==0))
-    return E_INVALIDARG;
-
-  /*
-   * Read the information from the property.
-   */
-  readSucessful = StorageImpl_ReadProperty(
-                    This->ancestorStorage,
-                    This->rootPropertySetIndex,
-                    &curProperty);
-
-  if (readSucessful)
-  {
-    StorageUtl_CopyPropertyToSTATSTG(
-      pstatstg, 
-      &curProperty, 
-      grfStatFlag);
-    
-    return S_OK;
-  }
-  
-  return E_FAIL;
-}
-
-/************************************************************************
- * Storage32BaseImpl_RenameElement (IStorage)
- *
- * This method will rename the specified element. 
- *
- * See Windows documentation for more details on IStorage methods.
- * 
- * Implementation notes: The method used to rename consists of creating a clone 
- *    of the deleted StgProperty object setting it with the new name and to 
- *    perform a DestroyElement of the old StgProperty.
- */
-HRESULT WINAPI StorageBaseImpl_RenameElement(
-            IStorage*        iface,
-            const OLECHAR*   pwcsOldName,  /* [in] */
-            const OLECHAR*   pwcsNewName)  /* [in] */
-{
-  ICOM_THIS(StorageBaseImpl,iface);
-  IEnumSTATSTGImpl* propertyEnumeration;
-  StgProperty       currentProperty;
-  ULONG             foundPropertyIndex;
-
-  TRACE("(%p, %s, %s)\n", 
-	iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
-
-  /*
-   * Create a property enumeration to search the properties
-   */
-  propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
-                                                   This->rootPropertySetIndex);
-
-  /*
-   * Search the enumeration for the new property name
-   */
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
-                                                     pwcsNewName,
-                                                     &currentProperty);
-
-  if (foundPropertyIndex != PROPERTY_NULL)
-  {
-    /*
-     * There is already a property with the new name
-     */
-    IEnumSTATSTGImpl_Destroy(propertyEnumeration);
-    return STG_E_FILEALREADYEXISTS;
-  }
-
-  IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
-
-  /*
-   * Search the enumeration for the old property name
-   */
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
-                                                     pwcsOldName,
-                                                     &currentProperty);
-
-  /*
-   * Delete the property enumeration since we don't need it anymore
-   */
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
-
-  if (foundPropertyIndex != PROPERTY_NULL)
-  {
-    StgProperty renamedProperty;
-    ULONG       renamedPropertyIndex;
-
-    /*
-     * Setup a new property for the renamed property
-     */
-    renamedProperty.sizeOfNameString = 
-      ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
-  
-    if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
-      return STG_E_INVALIDNAME;
-  
-    lstrcpyW(renamedProperty.name, pwcsNewName);
- 
-    renamedProperty.propertyType  = currentProperty.propertyType;
-    renamedProperty.startingBlock = currentProperty.startingBlock;
-    renamedProperty.size.LowPart  = currentProperty.size.LowPart;
-    renamedProperty.size.HighPart = currentProperty.size.HighPart;
-  
-    renamedProperty.previousProperty = PROPERTY_NULL;
-    renamedProperty.nextProperty     = PROPERTY_NULL;
-  
-    /*
-     * Bring the dirProperty link in case it is a storage and in which
-     * case the renamed storage elements don't require to be reorganized.
-     */
-    renamedProperty.dirProperty = currentProperty.dirProperty;
-  
-    /* call CoFileTime to get the current time 
-    renamedProperty.timeStampS1
-    renamedProperty.timeStampD1
-    renamedProperty.timeStampS2
-    renamedProperty.timeStampD2
-    renamedProperty.propertyUniqueID 
-    */
-  
-    /* 
-     * Obtain a free property in the property chain
-     */
-    renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
-  
-    /*
-     * Save the new property into the new property spot
-     */  
-    StorageImpl_WriteProperty(
-      This->ancestorStorage,
-      renamedPropertyIndex, 
-      &renamedProperty);
-  
-    /* 
-     * Find a spot in the property chain for our newly created property.
-     */
-    updatePropertyChain(
-      (StorageImpl*)This,
-      renamedPropertyIndex, 
-      renamedProperty);
-
-    /*
-     * At this point the renamed property has been inserted in the tree, 
-     * now, before to Destroy the old property we must zeroed it's dirProperty 
-     * otherwise the DestroyProperty below will zap it all and we do not want 
-     * this to happen.
-     * Also, we fake that the old property is a storage so the DestroyProperty
-     * will not do a SetSize(0) on the stream data.
-     * 
-     * This means that we need to tweek the StgProperty if it is a stream or a
-     * non empty storage.
-     */
-    StorageImpl_ReadProperty(This->ancestorStorage,
-                             foundPropertyIndex,
-                             &currentProperty);
-
-    currentProperty.dirProperty  = PROPERTY_NULL;
-    currentProperty.propertyType = PROPTYPE_STORAGE;
-    StorageImpl_WriteProperty(
-      This->ancestorStorage,
-      foundPropertyIndex, 
-      &currentProperty);
-
-    /* 
-     * Invoke Destroy to get rid of the ole property and automatically redo 
-     * the linking of it's previous and next members... 
-     */ 
-    StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName); 
-
-  }
-  else
-  {
-    /*
-     * There is no property with the old name
-     */
-    return STG_E_FILENOTFOUND;
-  }
-
-  return S_OK;
-}
-
-/************************************************************************
- * Storage32BaseImpl_CreateStream (IStorage)
- *
- * This method will create a stream object within this storage 
- *
- * See Windows documentation for more details on IStorage methods.
- */
-HRESULT WINAPI StorageBaseImpl_CreateStream(
-            IStorage*        iface,
-            const OLECHAR*   pwcsName,  /* [string][in] */
-            DWORD            grfMode,   /* [in] */
-            DWORD            reserved1, /* [in] */
-            DWORD            reserved2, /* [in] */
-            IStream**        ppstm)     /* [out] */
-{
-  ICOM_THIS(StorageBaseImpl,iface);
-  IEnumSTATSTGImpl* propertyEnumeration;
-  StgStreamImpl*    newStream;
-  StgProperty       currentProperty, newStreamProperty;
-  ULONG             foundPropertyIndex, newPropertyIndex;
-
-  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", 
-	iface, debugstr_w(pwcsName), grfMode, 
-	reserved1, reserved2, ppstm);
-
-  /*
-   * Validate parameters
-   */
-  if (ppstm == 0)
-    return STG_E_INVALIDPOINTER;
-
-  if (pwcsName == 0)
-    return STG_E_INVALIDNAME;
-
-  /*
-   * Validate the STGM flags
-   */
-  if ( FAILED( validateSTGM(grfMode) ))
-    return STG_E_INVALIDFLAG;
-
-  /*
-   * As documented.
-   */
-  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
-        (grfMode & STGM_DELETEONRELEASE) ||
-        (grfMode & STGM_TRANSACTED) )
-    return STG_E_INVALIDFUNCTION;
-
-  /*
-   * Initialize the out parameter
-   */
-  *ppstm = 0;
-
-  /*
-   * Create a property enumeration to search the properties
-   */
-  propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
-                                                   This->rootPropertySetIndex);
-
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
-                                                     pwcsName,
-                                                     &currentProperty);
-
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
-
-  if (foundPropertyIndex != PROPERTY_NULL)
-  {
-    /*
-     * An element with this name already exists 
-     */
-    if (grfMode & STGM_CREATE)
-    {
-      IStorage_DestroyElement(iface, pwcsName); 
-    }
-    else 
-      return STG_E_FILEALREADYEXISTS;
-  }
-
-  /* 
-   * memset the empty property 
-   */
-  memset(&newStreamProperty, 0, sizeof(StgProperty));
-
-  newStreamProperty.sizeOfNameString =
-      ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
-
-  if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
-    return STG_E_INVALIDNAME;
-
-  lstrcpyW(newStreamProperty.name, pwcsName);
-
-  newStreamProperty.propertyType  = PROPTYPE_STREAM;
-  newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
-  newStreamProperty.size.LowPart  = 0;
-  newStreamProperty.size.HighPart = 0;
-
-  newStreamProperty.previousProperty = PROPERTY_NULL;
-  newStreamProperty.nextProperty     = PROPERTY_NULL;
-  newStreamProperty.dirProperty      = PROPERTY_NULL;
-
-  /* call CoFileTime to get the current time 
-  newStreamProperty.timeStampS1
-  newStreamProperty.timeStampD1
-  newStreamProperty.timeStampS2
-  newStreamProperty.timeStampD2
-  */
-
-  /*  newStreamProperty.propertyUniqueID */
-
-  /*
-   * Get a free property or create a new one 
-   */
-  newPropertyIndex = getFreeProperty(This->ancestorStorage);
-
-  /*
-   * Save the new property into the new property spot
-   */  
-  StorageImpl_WriteProperty(
-    This->ancestorStorage,
-    newPropertyIndex, 
-    &newStreamProperty);
-
-  /* 
-   * Find a spot in the property chain for our newly created property.
-   */
-  updatePropertyChain(
-    (StorageImpl*)This,
-    newPropertyIndex, 
-    newStreamProperty);
-
-  /* 
-   * Open the stream to return it.
-   */
-  newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);
-
-  if (newStream != 0)
-  {
-    *ppstm = (IStream*)newStream;
-
-    /*
-     * Since we are returning a pointer to the interface, we have to nail down
-     * the reference.
-     */
-    StgStreamImpl_AddRef(*ppstm);
-  }
-  else
-  {
-    return STG_E_INSUFFICIENTMEMORY;
-  }
-
-  return S_OK;
-}
-
-/************************************************************************
- * Storage32BaseImpl_SetClass (IStorage)
- *
- * This method will write the specified CLSID in the property of this 
- * storage.
- *
- * See Windows documentation for more details on IStorage methods.
- */
-HRESULT WINAPI StorageBaseImpl_SetClass(
-  IStorage*        iface,
-  REFCLSID         clsid) /* [in] */
-{
-  ICOM_THIS(StorageBaseImpl,iface);
-  HRESULT hRes = E_FAIL;
-  StgProperty curProperty;
-  BOOL success;
-
-  TRACE("(%p, %p)\n", iface, clsid);
-  
-  success = StorageImpl_ReadProperty(This->ancestorStorage,
-                                       This->rootPropertySetIndex,
-                                       &curProperty);
-  if (success)
-  {
-    curProperty.propertyUniqueID = *clsid;
-
-    success =  StorageImpl_WriteProperty(This->ancestorStorage,
-                                           This->rootPropertySetIndex,
-                                           &curProperty);
-    if (success)
-      hRes = S_OK;
-  }
-
-  return hRes;
-}
-
-/************************************************************************
-** Storage32Impl implementation
-*/
-        
-/************************************************************************
- * Storage32Impl_CreateStorage (IStorage)
- *
- * This method will create the storage object within the provided storage.
- *
- * See Windows documentation for more details on IStorage methods.
- */
-HRESULT WINAPI StorageImpl_CreateStorage( 
-  IStorage*      iface,
-  const OLECHAR  *pwcsName, /* [string][in] */ 
-  DWORD            grfMode,   /* [in] */ 
-  DWORD            reserved1, /* [in] */ 
-  DWORD            reserved2, /* [in] */ 
-  IStorage       **ppstg)   /* [out] */ 
-{
-  StorageImpl* const This=(StorageImpl*)iface;
-
-  IEnumSTATSTGImpl *propertyEnumeration;
-  StgProperty      currentProperty;
-  StgProperty      newProperty;
-  ULONG            foundPropertyIndex;
-  ULONG            newPropertyIndex;
-  HRESULT          hr;
-
-  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", 
-	iface, debugstr_w(pwcsName), grfMode, 
-	reserved1, reserved2, ppstg);
-  
-  /*
-   * Validate parameters
-   */
-  if (ppstg == 0)
-    return STG_E_INVALIDPOINTER;
-
-  if (pwcsName == 0)
-    return STG_E_INVALIDNAME;
-
-  /*
-   * Validate the STGM flags
-   */
-  if ( FAILED( validateSTGM(grfMode) ) ||
-       (grfMode & STGM_DELETEONRELEASE) )
-    return STG_E_INVALIDFLAG;
-
-  /*
-   * Initialize the out parameter
-   */
-  *ppstg = 0;
-
-  /*
-   * Create a property enumeration and search the properties
-   */
-  propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
-                                                    This->rootPropertySetIndex);
-
-  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
-                                                     pwcsName,
-                                                     &currentProperty);
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
-
-  if (foundPropertyIndex != PROPERTY_NULL)
-  {
-    /*
-     * An element with this name already exists 
-     */
-    if (grfMode & STGM_CREATE)
-      IStorage_DestroyElement(iface, pwcsName); 
-    else 
-      return STG_E_FILEALREADYEXISTS;
-  }
-
-  /* 
-   * memset the empty property 
-   */
-  memset(&newProperty, 0, sizeof(StgProperty));
-
-  newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
-
-  if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
-    return STG_E_INVALIDNAME;
-
-  lstrcpyW(newProperty.name, pwcsName);
-
-  newProperty.propertyType  = PROPTYPE_STORAGE;
-  newProperty.startingBlock = BLOCK_END_OF_CHAIN;
-  newProperty.size.LowPart  = 0;
-  newProperty.size.HighPart = 0;
-
-  newProperty.previousProperty = PROPERTY_NULL;
-  newProperty.nextProperty     = PROPERTY_NULL;
-  newProperty.dirProperty      = PROPERTY_NULL;
-
-  /* call CoFileTime to get the current time 
-  newProperty.timeStampS1
-  newProperty.timeStampD1
-  newProperty.timeStampS2
-  newProperty.timeStampD2
-  */
-
-  /*  newStorageProperty.propertyUniqueID */
-
-  /* 
-   * Obtain a free property in the property chain
-   */
-  newPropertyIndex = getFreeProperty(This->ancestorStorage);
-
-  /*
-   * Save the new property into the new property spot
-   */  
-  StorageImpl_WriteProperty(
-    This->ancestorStorage,
-    newPropertyIndex, 
-    &newProperty);
-
-  /* 
-   * Find a spot in the property chain for our newly created property.
-   */
-  updatePropertyChain(
-    This,
-    newPropertyIndex, 
-    newProperty);
-
-  /* 
-   * Open it to get a pointer to return.
-   */
-  hr = IStorage_OpenStorage(
-         iface,
-         (OLECHAR*)pwcsName,
-         0,
-         grfMode,
-         0,
-         0,
-         ppstg);
-
-  if( (hr != S_OK) || (*ppstg == NULL))
-  {
-    return hr;
-  }
-
-  
-  return S_OK;
-}
-
-
-/***************************************************************************
- *
- * Internal Method
- *
- * Get a free property or create a new one.
- */
-static ULONG getFreeProperty(
-  StorageImpl *storage)
-{
-  ULONG       currentPropertyIndex = 0;
-  ULONG       newPropertyIndex     = PROPERTY_NULL;
-  BOOL      readSucessful        = TRUE;
-  StgProperty currentProperty;
-
-  do
-  {
-    /*
-     * Start by reading the root property
-     */
-    readSucessful = StorageImpl_ReadProperty(storage->ancestorStorage,
-                                               currentPropertyIndex,
-                                               &currentProperty);
-    if (readSucessful)
-    {
-      if (currentProperty.sizeOfNameString == 0)
-      {
-        /* 
-         * The property existis and is available, we found it.
-         */
-        newPropertyIndex = currentPropertyIndex;
-      }
-    }
-    else
-    {
-      /*
-       * We exhausted the property list, we will create more space below
-       */
-      newPropertyIndex = currentPropertyIndex;
-    }
-    currentPropertyIndex++;
-
-  } while (newPropertyIndex == PROPERTY_NULL);
-
-  /* 
-   * grow the property chain 
-   */
-  if (! readSucessful)
-  {
-    StgProperty    emptyProperty;
-    ULARGE_INTEGER newSize;
-    ULONG          propertyIndex;
-    ULONG          lastProperty  = 0;
-    ULONG          blockCount    = 0;
-
-    /* 
-     * obtain the new count of property blocks 
-     */
-    blockCount = BlockChainStream_GetCount(
-                   storage->ancestorStorage->rootBlockChain)+1;
-
-    /* 
-     * initialize the size used by the property stream 
-     */
-    newSize.HighPart = 0;
-    newSize.LowPart  = storage->bigBlockSize * blockCount;
-
-    /* 
-     * add a property block to the property chain 
-     */
-    BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
-
-    /* 
-     * memset the empty property in order to initialize the unused newly 
-     * created property
-     */
-    memset(&emptyProperty, 0, sizeof(StgProperty));
-
-    /* 
-     * initialize them
-     */
-    lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount; 
-    
-    for(
-      propertyIndex = newPropertyIndex;
-      propertyIndex < lastProperty;
-      propertyIndex++)
-    {
-      StorageImpl_WriteProperty(
-        storage->ancestorStorage,
-        propertyIndex, 
-        &emptyProperty);
-    }
-  }
-
-  return newPropertyIndex;
-}
-
-/****************************************************************************
- *
- * Internal Method
- *
- * Case insensitive comparaison of StgProperty.name by first considering 
- * their size.
- *
- * Returns <0 when newPrpoerty < currentProperty
- *         >0 when newPrpoerty > currentProperty
- *          0 when newPrpoerty == currentProperty
- */
-static LONG propertyNameCmp(
-  OLECHAR *newProperty,
-  OLECHAR *currentProperty)
-{
-  LONG diff      = lstrlenW(newProperty) - lstrlenW(currentProperty);
-
-  if (diff == 0) 
-  {
-    /* 
-     * We compare the string themselves only when they are of the same lenght
-     */
-    diff = lstrcmpiW( newProperty, currentProperty);
-  }
-
-  return diff;  
-}
-
-/****************************************************************************
- *
- * Internal Method
- *
- * Properly link this new element in the property chain.
- */
-static void updatePropertyChain(
-  StorageImpl *storage,
-  ULONG         newPropertyIndex,
-  StgProperty   newProperty) 
-{
-  StgProperty currentProperty;
-
-  /*
-   * Read the root property
-   */
-  StorageImpl_ReadProperty(storage->ancestorStorage,
-                             storage->rootPropertySetIndex,
-                             &currentProperty);
-
-  if (currentProperty.dirProperty != PROPERTY_NULL)
-  {
-    /* 
-     * The root storage contains some element, therefore, start the research
-     * for the appropriate location.
-     */
-    BOOL found = 0;
-    ULONG  current, next, previous, currentPropertyId;
-
-    /*
-     * Keep the StgProperty sequence number of the storage first property
-     */
-    currentPropertyId = currentProperty.dirProperty;
-
-    /*
-     * Read 
-     */
-    StorageImpl_ReadProperty(storage->ancestorStorage,
-                               currentProperty.dirProperty,
-                               &currentProperty);
-
-    previous = currentProperty.previousProperty;
-    next     = currentProperty.nextProperty;
-    current  = currentPropertyId;
-
-    while (found == 0)
-    {
-      LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
-  
-      if (diff < 0)
-      {
-        if (previous != PROPERTY_NULL)
-        {
-          StorageImpl_ReadProperty(storage->ancestorStorage,
-                                     previous,
-                                     &currentProperty);
-          current = previous;
-        }
-        else
-        {
-          currentProperty.previousProperty = newPropertyIndex;
-          StorageImpl_WriteProperty(storage->ancestorStorage,
-                                      current,
-                                      &currentProperty);
-          found = 1;
-        }
-      }
-      else if (diff > 0)
-      {
-        if (next != PROPERTY_NULL)
-        {
-          StorageImpl_ReadProperty(storage->ancestorStorage,
-                                     next,
-                                     &currentProperty);
-          current = next;
-        }
-        else
-        {
-          currentProperty.nextProperty = newPropertyIndex;
-          StorageImpl_WriteProperty(storage->ancestorStorage,
-                                      current,
-                                      &currentProperty);
-          found = 1;
-        }
-      }
-      else
-      {
-	/*
-	 * Trying to insert an item with the same name in the
-	 * subtree structure.
-	 */
-	assert(FALSE);
-      }
-
-      previous = currentProperty.previousProperty;
-      next     = currentProperty.nextProperty;
-    }
-  }
-  else
-  {
-    /* 
-     * The root storage is empty, link the new property to it's dir property
-     */
-    currentProperty.dirProperty = newPropertyIndex;
-    StorageImpl_WriteProperty(storage->ancestorStorage,
-                                storage->rootPropertySetIndex,
-                                &currentProperty);
-  }
-}
-
-      
-/*************************************************************************
- * CopyTo (IStorage)
- */
-HRESULT WINAPI StorageImpl_CopyTo( 
-  IStorage*   iface,
-  DWORD       ciidExclude,  /* [in] */ 
-  const IID*  rgiidExclude, /* [size_is][unique][in] */ 
-  SNB         snbExclude,   /* [unique][in] */ 
-  IStorage*   pstgDest)     /* [unique][in] */ 
-{
-  IEnumSTATSTG *elements     = 0;
-  STATSTG      curElement, strStat;
-  HRESULT      hr;
-  IStorage     *pstgTmp, *pstgChild;
-  IStream      *pstrTmp, *pstrChild;
-
-  if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
-    FIXME("Exclude option not implemented\n");
-
-  TRACE("(%p, %ld, %p, %p, %p)\n", 
-	iface, ciidExclude, rgiidExclude, 
-	snbExclude, pstgDest);
-
-  /*
-   * Perform a sanity check
-   */
-  if ( pstgDest == 0 )
-    return STG_E_INVALIDPOINTER;
-
-  /* 
-   * Enumerate the elements
-   */
-  hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
-
-  if ( hr != S_OK )
-    return hr;
-
-  /*
-   * set the class ID
-   */
-  IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
-  IStorage_SetClass( pstgDest, &curElement.clsid );
-  
-  do
-  {
-    /*
-     * Obtain the next element
-     */
-    hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
-
-    if ( hr == S_FALSE )
-    {
-      hr = S_OK;   /* done, every element has been copied */
-      break;
-    }
-
-    if (curElement.type == STGTY_STORAGE)
-    {
-      /*
-       * open child source storage
-       */
-      hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
-				 STGM_READ|STGM_SHARE_EXCLUSIVE,
-				 NULL, 0, &pstgChild );
-
-      if (hr != S_OK)
-        break;
-
-      /*
-       * Check if destination storage is not a child of the source
-       * storage, which will cause an infinite loop
-       */
-      if (pstgChild == pstgDest)
-      {
-	IEnumSTATSTG_Release(elements);
-
-	return STG_E_ACCESSDENIED;
-      }
-            
-      /*
-       * create a new storage in destination storage
-       */
-      hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
-                                   STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
-				   0, 0,
-                                   &pstgTmp );
-      /*
-       * if it already exist, don't create a new one use this one
-       */
-      if (hr == STG_E_FILEALREADYEXISTS)
-      {
-        hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
-                                   STGM_WRITE|STGM_SHARE_EXCLUSIVE,
-                                   NULL, 0, &pstgTmp );
-      }
-        
-      if (hr != S_OK)
-        break;
-
-        
-      /*
-       * do the copy recursively
-       */
-      hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
-                               snbExclude, pstgTmp );
-                                
-      IStorage_Release( pstgTmp );
-      IStorage_Release( pstgChild );
-    }
-    else if (curElement.type == STGTY_STREAM)
-    {
-      /*
-       * create a new stream in destination storage. If the stream already
-       * exist, it will be deleted and a new one will be created.
-       */
-      hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
-                                  STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
-                                  0, 0, &pstrTmp );
-
-      if (hr != S_OK)
-        break;
-
-      /*
-       * open child stream storage
-       */
-      hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
-				STGM_READ|STGM_SHARE_EXCLUSIVE,
-				0, &pstrChild );
-
-      if (hr != S_OK)
-        break;
-
-      /*
-       * Get the size of the source stream
-       */
-      IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
-
-      /*
-       * Set the size of the destination stream.
-       */
-      IStream_SetSize(pstrTmp, strStat.cbSize);
-      
-      /*
-       * do the copy
-       */
-      hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
-                           NULL, NULL );
-                                
-      IStream_Release( pstrTmp );
-      IStream_Release( pstrChild );
-    }
-    else
-    {
-      WARN("unknown element type: %ld\n", curElement.type);
-    }
-
-  } while (hr == S_OK);
-
-  /*
-   * Clean-up
-   */
-  IEnumSTATSTG_Release(elements);
-  
-  return hr;
-}
-        
-/*************************************************************************
- * MoveElementTo (IStorage)
- */
-HRESULT WINAPI StorageImpl_MoveElementTo( 
-  IStorage*     iface,
-  const OLECHAR *pwcsName,   /* [string][in] */ 
-  IStorage      *pstgDest,   /* [unique][in] */ 
-  const OLECHAR *pwcsNewName,/* [string][in] */ 
-  DWORD           grfFlags)    /* [in] */ 
-{
-  FIXME("not implemented!\n");
-  return E_NOTIMPL;
-}
-        
-/*************************************************************************
- * Commit (IStorage)
- */
-HRESULT WINAPI StorageImpl_Commit( 
-  IStorage*   iface,
-  DWORD         grfCommitFlags)/* [in] */ 
-{
-  FIXME("(%ld): stub!\n", grfCommitFlags);
-  return S_OK;
-}
-        
-/*************************************************************************
- * Revert (IStorage)
- */
-HRESULT WINAPI StorageImpl_Revert( 
-  IStorage* iface)
-{
-  FIXME("not implemented!\n");
-  return E_NOTIMPL;
-}
-
-/*************************************************************************
- * DestroyElement (IStorage)
- *
- * Stategy: This implementation is build this way for simplicity not for speed. 
- *          I always delete the top most element of the enumeration and adjust
- *          the deleted element pointer all the time.  This takes longer to 
- *          do but allow to reinvoke DestroyElement whenever we encounter a 
- *          storage object.  The optimisation reside in the usage of another
- *          enumeration stategy that would give all the leaves of a storage 
- *          first. (postfix order)
- */
-HRESULT WINAPI StorageImpl_DestroyElement( 
-  IStorage*     iface,
-  const OLECHAR *pwcsName)/* [string][in] */ 
-{
-  StorageImpl* const This=(StorageImpl*)iface;
-
-  IEnumSTATSTGImpl* propertyEnumeration;
-  HRESULT           hr = S_OK;
-  BOOL            res;
-  StgProperty       propertyToDelete;
-  StgProperty       parentProperty;
-  ULONG             foundPropertyIndexToDelete;
-  ULONG             typeOfRelation;
-  ULONG             parentPropertyId;
-
-  TRACE("(%p, %s)\n", 
-	iface, debugstr_w(pwcsName));
-
-  /*
-   * Perform a sanity check on the parameters.
-   */
-  if (pwcsName==NULL) 
-    return STG_E_INVALIDPOINTER;
-  
-  /*
-   * Create a property enumeration to search the property with the given name
-   */
-  propertyEnumeration = IEnumSTATSTGImpl_Construct(
-    This->ancestorStorage, 
-    This->rootPropertySetIndex);
-  
-  foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
-    propertyEnumeration,
-    pwcsName,
-    &propertyToDelete);
-
-  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
-
-  if ( foundPropertyIndexToDelete == PROPERTY_NULL )  
-  {
-    return STG_E_FILENOTFOUND;
-  }
-
-  /* 
-   * Find the parent property of the property to delete (the one that 
-   * link to it).  If This->dirProperty == foundPropertyIndexToDelete, 
-   * the parent is This. Otherwise, the parent is one of it's sibling...
-   */
-
-  /* 
-   * First, read This's StgProperty..
-   */
-  res = StorageImpl_ReadProperty( 
-          This->ancestorStorage,
-          This->rootPropertySetIndex,
-          &parentProperty);
-
-  assert(res==TRUE);
-
-  /* 
-   * Second, check to see if by any chance the actual storage (This) is not
-   * the parent of the property to delete... We never know...
-   */
-  if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
-  {
-    /* 
-     * Set data as it would have been done in the else part...
-     */
-    typeOfRelation   = PROPERTY_RELATION_DIR;
-    parentPropertyId = This->rootPropertySetIndex;
-  }
-  else 
-  { 
-    /*
-     * Create a property enumeration to search the parent properties, and 
-     * delete it once done.
-     */
-    IEnumSTATSTGImpl* propertyEnumeration2;
-
-    propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
-      This->ancestorStorage, 
-      This->rootPropertySetIndex);
-  
-    typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
-      propertyEnumeration2,
-      foundPropertyIndexToDelete,
-      &parentProperty,
-      &parentPropertyId);
-
-    IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
-  }
-
-  if ( propertyToDelete.propertyType == PROPTYPE_STORAGE ) 
-  {
-    hr = deleteStorageProperty(
-           This, 
-           foundPropertyIndexToDelete,
-           propertyToDelete);
-  } 
-  else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
-  {
-    hr = deleteStreamProperty(
-           This, 
-           foundPropertyIndexToDelete,
-           propertyToDelete);
-  }
-
-  if (hr!=S_OK) 
-    return hr;
-
-  /*
-   * Adjust the property chain
-   */
-  hr = adjustPropertyChain(
-        This,
-        propertyToDelete, 
-        parentProperty,
-        parentPropertyId,
-        typeOfRelation);
-
-  return hr;
-}
-
-
-/*********************************************************************
- *
- * Internal Method
- *
- * Perform the deletion of a complete storage node
- *
- */
-static HRESULT deleteStorageProperty(
-  StorageImpl *parentStorage,
-  ULONG        indexOfPropertyToDelete,
-  StgProperty  propertyToDelete)
-{
-  IEnumSTATSTG *elements     = 0;
-  IStorage   *childStorage = 0;
-  STATSTG      currentElement;
-  HRESULT      hr;
-  HRESULT      destroyHr = S_OK;
-
-  /*
-   * Open the storage and enumerate it
-   */
-  hr = StorageBaseImpl_OpenStorage(
-        (IStorage*)parentStorage,
-        propertyToDelete.name,
-        0,
-        STGM_SHARE_EXCLUSIVE,
-        0,
-        0,
-        &childStorage);
-
-  if (hr != S_OK)
-  {
-    return hr;
-  }
-
-  /* 
-   * Enumerate the elements
-   */
-  IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
-
-  do
-  {
-    /*
-     * Obtain the next element
-     */
-    hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
-    if (hr==S_OK)
-    {
-      destroyHr = StorageImpl_DestroyElement(
-                    (IStorage*)childStorage, 
-                    (OLECHAR*)currentElement.pwcsName);
-
-      CoTaskMemFree(currentElement.pwcsName);
-    }
-
-    /*
-     * We need to Reset the enumeration every time because we delete elements
-     * and the enumeration could be invalid
-     */
-    IEnumSTATSTG_Reset(elements);
-
-  } while ((hr == S_OK) && (destroyHr == S_OK));
-
-  /*
-   * Invalidate the property by zeroing it's name member.
-   */
-  propertyToDelete.sizeOfNameString = 0;
-
-  StorageImpl_WriteProperty(parentStorage->ancestorStorage,
-                            indexOfPropertyToDelete,
-                            &propertyToDelete);
-
-  IStorage_Release(childStorage);
-  IEnumSTATSTG_Release(elements);
-    
-  return destroyHr;
-}
-
-/*********************************************************************
- *
- * Internal Method
- *
- * Perform the deletion of a stream node
- *
- */
-static HRESULT deleteStreamProperty(
-  StorageImpl *parentStorage,
-  ULONG         indexOfPropertyToDelete,
-  StgProperty   propertyToDelete)
-{
-  IStream      *pis;
-  HRESULT        hr;
-  ULARGE_INTEGER size;
-
-  size.HighPart = 0;
-  size.LowPart = 0;
-
-  hr = StorageBaseImpl_OpenStream(
-         (IStorage*)parentStorage,
-         (OLECHAR*)propertyToDelete.name,
-         NULL,
-         STGM_WRITE | STGM_SHARE_EXCLUSIVE,
-         0,
-         &pis);
-    
-  if (hr!=S_OK)
-  {
-    return(hr);
-  }
-
-  /* 
-   * Zap the stream 
-   */ 
-  hr = IStream_SetSize(pis, size); 
-
-  if(hr != S_OK)
-  {
-    return hr;
-  }
-
-  /*
-   * Release the stream object.
-   */
-  IStream_Release(pis);
-
-  /* 
-   * Invalidate the property by zeroing it's name member.
-   */
-  propertyToDelete.sizeOfNameString = 0;
-
-  /* 
-   * Here we should re-read the property so we get the updated pointer
-   * but since we are here to zap it, I don't do it...
-   */
-  StorageImpl_WriteProperty(
-    parentStorage->ancestorStorage, 
-    indexOfPropertyToDelete,
-    &propertyToDelete);
-
-  return S_OK;
-}
-
-/*********************************************************************
- *
- * Internal Method
- *
- * Finds a placeholder for the StgProperty within the Storage
- *
- */
-static HRESULT findPlaceholder(
-  StorageImpl *storage,
-  ULONG         propertyIndexToStore,
-  ULONG         storePropertyIndex,
-  INT         typeOfRelation)
-{
-  StgProperty storeProperty;
-  HRESULT     hr = S_OK;
-  BOOL      res = TRUE;
-
-  /*
-   * Read the storage property
-   */
-  res = StorageImpl_ReadProperty(
-          storage->ancestorStorage,
-          storePropertyIndex, 
-          &storeProperty);
-
-  if(! res)
-  {
-    return E_FAIL;
-  }
-
-  if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
-  {
-    if (storeProperty.previousProperty != PROPERTY_NULL)
-    {
-      return findPlaceholder(
-               storage,
-               propertyIndexToStore, 
-               storeProperty.previousProperty,
-               typeOfRelation);
-    }
-    else
-    {
-      storeProperty.previousProperty = propertyIndexToStore;
-    }
-  }
-  else if (typeOfRelation == PROPERTY_RELATION_NEXT)
-  {
-    if (storeProperty.nextProperty != PROPERTY_NULL)
-    {
-      return findPlaceholder(
-               storage,
-               propertyIndexToStore, 
-               storeProperty.nextProperty,
-               typeOfRelation);
-    }
-    else
-    {
-      storeProperty.nextProperty = propertyIndexToStore;
-    }
-  } 
-  else if (typeOfRelation == PROPERTY_RELATION_DIR)
-  {
-    if (storeProperty.dirProperty != PROPERTY_NULL)
-    {
-      return findPlaceholder(
-               storage,
-               propertyIndexToStore, 
-               storeProperty.dirProperty,
-               typeOfRelation);
-    }
-    else
-    {
-      storeProperty.dirProperty = propertyIndexToStore;
-    }
-  }
-
-  hr = StorageImpl_WriteProperty(
-         storage->ancestorStorage,
-         storePropertyIndex, 
-         &storeProperty);
-
-  if(! hr)
-  {
-    return E_FAIL;
-  }
-
-  return S_OK;
-}
-
-/*************************************************************************
- *
- * Internal Method
- *
- * This method takes the previous and the next property link of a property 
- * to be deleted and find them a place in the Storage.
- */
-static HRESULT adjustPropertyChain( 
-  StorageImpl *This,
-  StgProperty   propertyToDelete,
-  StgProperty   parentProperty,
-  ULONG         parentPropertyId,
-  INT         typeOfRelation)
-{
-  ULONG   newLinkProperty        = PROPERTY_NULL;
-  BOOL  needToFindAPlaceholder = FALSE;
-  ULONG   storeNode              = PROPERTY_NULL;
-  ULONG   toStoreNode            = PROPERTY_NULL;
-  INT   relationType           = 0;
-  HRESULT hr                     = S_OK;
-  BOOL  res                    = TRUE;
-  
-  if (typeOfRelation == PROPERTY_RELATION_PREVIOUS) 
-  {
-    if (propertyToDelete.previousProperty != PROPERTY_NULL)  
-    {
-      /* 
-       * Set the parent previous to the property to delete previous
-       */
-      newLinkProperty = propertyToDelete.previousProperty;
-
-      if (propertyToDelete.nextProperty != PROPERTY_NULL)  
-      {
-        /*
-         * We also need to find a storage for the other link, setup variables 
-         * to do this at the end...
-         */      
-        needToFindAPlaceholder = TRUE;
-        storeNode              = propertyToDelete.previousProperty;
-        toStoreNode            = propertyToDelete.nextProperty;
-        relationType           = PROPERTY_RELATION_NEXT;
-      }
-    } 
-    else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
-    {
-      /* 
-       * Set the parent previous to the property to delete next
-       */
-      newLinkProperty = propertyToDelete.nextProperty;
-    }
-   
-    /* 
-     * Link it for real...
-     */ 
-    parentProperty.previousProperty = newLinkProperty;
-  
-  } 
-  else if (typeOfRelation == PROPERTY_RELATION_NEXT) 
-  {
-    if (propertyToDelete.previousProperty != PROPERTY_NULL)  
-    {
-      /* 
-       * Set the parent next to the property to delete next previous
-       */
-      newLinkProperty = propertyToDelete.previousProperty;
-      
-      if (propertyToDelete.nextProperty != PROPERTY_NULL)  
-      {
-        /*
-         * We also need to find a storage for the other link, setup variables 
-         * to do this at the end...
-         */      
-        needToFindAPlaceholder = TRUE;
-        storeNode              = propertyToDelete.previousProperty;
-        toStoreNode            = propertyToDelete.nextProperty;
-        relationType           = PROPERTY_RELATION_NEXT;
-      }
-    } 
-    else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
-    {
-      /* 
-       * Set the parent next to the property to delete next
-       */
-      newLinkProperty = propertyToDelete.nextProperty;
-    }
-
-    /* 
-     * Link it for real...
-     */ 
-    parentProperty.nextProperty = newLinkProperty;
-  } 
-  else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
-  {
-    if (propertyToDelete.previousProperty != PROPERTY_NULL) 
-    {
-      /* 
-       * Set the parent dir to the property to delete previous
-       */
-      newLinkProperty = propertyToDelete.previousProperty;
-
-      if (propertyToDelete.nextProperty != PROPERTY_NULL)  
-      {
-        /*
-         * We also need to find a storage for the other link, setup variables 
-         * to do this at the end...
-         */      
-        needToFindAPlaceholder = TRUE;
-        storeNode              = propertyToDelete.previousProperty;
-        toStoreNode            = propertyToDelete.nextProperty;
-        relationType           = PROPERTY_RELATION_NEXT;
-      }
-    } 
-    else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
-    {
-      /* 
-       * Set the parent dir to the property to delete next
-       */
-      newLinkProperty = propertyToDelete.nextProperty;
-    }
-
-    /* 
-     * Link it for real...
-     */ 
-    parentProperty.dirProperty = newLinkProperty;
-  }
-
-  /* 
-   * Write back the parent property    
-   */
-  res = StorageImpl_WriteProperty(
-          This->ancestorStorage, 
-          parentPropertyId,
-          &parentProperty);
-  if(! res)
-  {
-    return E_FAIL;
-  }
-
-  /*
-   * If a placeholder is required for the other link, then, find one and 
-   * get out of here...
-   */
-  if (needToFindAPlaceholder) 
-  {
-    hr = findPlaceholder(
-           This, 
-           toStoreNode, 
-           storeNode,
-           relationType);
-  }
-
-  return hr;
-}
-
-
-/******************************************************************************
- * SetElementTimes (IStorage)
- */
-HRESULT WINAPI StorageImpl_SetElementTimes( 
-  IStorage*     iface,
-  const OLECHAR *pwcsName,/* [string][in] */ 
-  const FILETIME  *pctime,  /* [in] */ 
-  const FILETIME  *patime,  /* [in] */ 
-  const FILETIME  *pmtime)  /* [in] */ 
-{
-  FIXME("not implemented!\n");
-  return E_NOTIMPL;
-}
-
-/******************************************************************************
- * SetStateBits (IStorage)
- */
-HRESULT WINAPI StorageImpl_SetStateBits( 
-  IStorage*   iface,
-  DWORD         grfStateBits,/* [in] */ 
-  DWORD         grfMask)     /* [in] */ 
-{
-  FIXME("not implemented!\n");
-  return E_NOTIMPL;
-}
-
-HRESULT StorageImpl_Construct(
-  StorageImpl* This,
-  HANDLE       hFile,
-  ILockBytes*  pLkbyt,
-  DWORD        openFlags,
-  BOOL         fileBased,
-  BOOL         fileCreate)
-{
-  HRESULT     hr = S_OK;
-  StgProperty currentProperty;
-  BOOL      readSucessful;
-  ULONG       currentPropertyIndex;
-  
-  if ( FAILED( validateSTGM(openFlags) ))
-    return STG_E_INVALIDFLAG;
-
-  memset(This, 0, sizeof(StorageImpl));
-  
-  /*
-   * Initialize the virtual fgunction table.
-   */
-  ICOM_VTBL(This)    = &Storage32Impl_Vtbl;
-  This->v_destructor = &StorageImpl_Destroy;
-  
-  /*
-   * This is the top-level storage so initialize the ancester pointer
-   * to this.
-   */
-  This->ancestorStorage = This;
-  
-  /*
-   * Initialize the physical support of the storage.
-   */
-  This->hFile = hFile;
-  
-  /*
-   * Initialize the big block cache.
-   */
-  This->bigBlockSize   = DEF_BIG_BLOCK_SIZE;
-  This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
-  This->bigBlockFile   = BIGBLOCKFILE_Construct(hFile,
-                                                pLkbyt,
-                                                openFlags,
-                                                This->bigBlockSize,
-                                                fileBased);
-
-  if (This->bigBlockFile == 0)
-    return E_FAIL;
- 
-  if (fileCreate)
-  {
-    ULARGE_INTEGER size;
-    BYTE* bigBlockBuffer;
-
-    /*
-     * Initialize all header variables:
-     * - The big block depot consists of one block and it is at block 0
-     * - The properties start at block 1
-     * - There is no small block depot
-     */
-    memset( This->bigBlockDepotStart,     
-            BLOCK_UNUSED, 
-            sizeof(This->bigBlockDepotStart));
-
-    This->bigBlockDepotCount    = 1;
-    This->bigBlockDepotStart[0] = 0;
-    This->rootStartBlock        = 1;
-    This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;
-    This->bigBlockSizeBits      = DEF_BIG_BLOCK_SIZE_BITS;
-    This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;
-    This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
-    This->extBigBlockDepotCount = 0;
-    StorageImpl_SaveFileHeader(This);
-
-    /*
-     * Add one block for the big block depot and one block for the properties
-     */
-    size.HighPart = 0;
-    size.LowPart  = This->bigBlockSize * 3;
-    BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
-
-    /*
-     * Initialize the big block depot
-     */
-    bigBlockBuffer = (BYTE *)StorageImpl_GetBigBlock(This, 0);
-    memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
-    StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
-    StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
-    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
-  }
-  else
-  {
-    /*
-     * Load the header for the file.
-     */
-    hr = StorageImpl_LoadFileHeader(This);
-
-    if (FAILED(hr))
-    {
-      BIGBLOCKFILE_Destructor(This->bigBlockFile);
-
-      return hr;
-    }
-  }
-
-  /*
-   * There is no block depot cached yet.
-   */
-  This->indexBlockDepotCached = 0xFFFFFFFF;
-
-  /*
-   * Start searching for free blocks with block 0.
-   */
-  This->prevFreeBlock = 0;
-  
-  /*
-   * Create the block chain abstractions.
-   */
-  This->rootBlockChain = 
-    BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
-
-  This->smallBlockDepotChain = BlockChainStream_Construct(
-                                 This, 
-                                 &This->smallBlockDepotStart, 
-                                 PROPERTY_NULL);
-
-  /*
-   * Write the root property 
-   */
-  if (fileCreate)
-  {
-    StgProperty rootProp;
-    /*
-     * Initialize the property chain
-     */
-    memset(&rootProp, 0, sizeof(rootProp));
-    lstrcpyAtoW(rootProp.name, (LPSTR)rootPropertyName);
-
-    rootProp.sizeOfNameString = (lstrlenW(rootProp.name)+1) * sizeof(WCHAR);
-    rootProp.propertyType     = PROPTYPE_ROOT;
-    rootProp.previousProperty = PROPERTY_NULL;
-    rootProp.nextProperty     = PROPERTY_NULL;
-    rootProp.dirProperty      = PROPERTY_NULL;
-    rootProp.startingBlock    = BLOCK_END_OF_CHAIN;
-    rootProp.size.HighPart    = 0;
-    rootProp.size.LowPart     = 0;
-
-    StorageImpl_WriteProperty(This, 0, &rootProp);
-  }
-
-  /*
-   * Find the ID of the root int he property sets.
-   */
-  currentPropertyIndex = 0;
-  
-  do
-  {
-    readSucessful = StorageImpl_ReadProperty(
-                      This, 
-                      currentPropertyIndex, 
-                      &currentProperty);
-    
-    if (readSucessful)
-    {
-      if ( (currentProperty.sizeOfNameString != 0 ) &&
-           (currentProperty.propertyType     == PROPTYPE_ROOT) )
-      {
-        This->rootPropertySetIndex = currentPropertyIndex;
-      }
-    }
-
-    currentPropertyIndex++;
-    
-  } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
-  
-  if (!readSucessful)
-  {
-    /* TODO CLEANUP */
-    return E_FAIL;
-  }
-
-  /*
-   * Create the block chain abstraction for the small block root chain.
-   */
-  This->smallBlockRootChain = BlockChainStream_Construct(
-                                This, 
-                                NULL, 
-                                This->rootPropertySetIndex);
-  
-  return hr;
-}
-
-void StorageImpl_Destroy(
-  StorageImpl* This)
-{
-  TRACE("(%p)\n", This);
-
-  BlockChainStream_Destroy(This->smallBlockRootChain);
-  BlockChainStream_Destroy(This->rootBlockChain);
-  BlockChainStream_Destroy(This->smallBlockDepotChain);
-
-  BIGBLOCKFILE_Destructor(This->bigBlockFile);
-  return;
-}
-
-/******************************************************************************
- *      Storage32Impl_GetNextFreeBigBlock
- *
- * Returns the index of the next free big block.
- * If the big block depot is filled, this method will enlarge it.
- *
- */
-ULONG StorageImpl_GetNextFreeBigBlock(
-  StorageImpl* This)
-{
-  ULONG depotBlockIndexPos;
-  void  *depotBuffer;
-  ULONG depotBlockOffset;
-  ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
-  ULONG nextBlockIndex    = BLOCK_SPECIAL;
-  int   depotIndex        = 0;
-  ULONG freeBlock         = BLOCK_UNUSED;
-
-  depotIndex = This->prevFreeBlock / blocksPerDepot;
-  depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
-
-  /*
-   * Scan the entire big block depot until we find a block marked free
-   */
-  while (nextBlockIndex != BLOCK_UNUSED)
-  {
-    if (depotIndex < COUNT_BBDEPOTINHEADER)
-    {
-      depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
-
-      /*
-       * Grow the primary depot.
-       */
-      if (depotBlockIndexPos == BLOCK_UNUSED)
-      {
-        depotBlockIndexPos = depotIndex*blocksPerDepot;
-
-        /*
-         * Add a block depot.
-         */
-        Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
-        This->bigBlockDepotCount++;
-        This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
-
-        /*
-         * Flag it as a block depot.
-         */
-        StorageImpl_SetNextBlockInChain(This,
-                                          depotBlockIndexPos,
-                                          BLOCK_SPECIAL);
-
-        /* Save new header information.
-         */
-        StorageImpl_SaveFileHeader(This);
-      }
-    }
-    else
-    {
-      depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
-
-      if (depotBlockIndexPos == BLOCK_UNUSED)
-      {
-        /*
-         * Grow the extended depot.
-         */
-        ULONG extIndex       = BLOCK_UNUSED;
-        ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;
-        ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
-
-        if (extBlockOffset == 0)
-        {
-          /* We need an extended block.
-           */
-          extIndex = Storage32Impl_AddExtBlockDepot(This);
-          This->extBigBlockDepotCount++;
-          depotBlockIndexPos = extIndex + 1;
-        }
-        else
-          depotBlockIndexPos = depotIndex * blocksPerDepot;
-
-        /*
-         * Add a block depot and mark it in the extended block.
-         */
-        Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
-        This->bigBlockDepotCount++;
-        Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
-
-        /* Flag the block depot.
-         */
-        StorageImpl_SetNextBlockInChain(This,
-                                          depotBlockIndexPos,
-                                          BLOCK_SPECIAL);
-
-        /* If necessary, flag the extended depot block.
-         */
-        if (extIndex != BLOCK_UNUSED)
-          StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
-
-        /* Save header information.
-         */
-        StorageImpl_SaveFileHeader(This);
-      }
-    }
-
-    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
-
-    if (depotBuffer != 0)
-    {
-      while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
-              ( nextBlockIndex != BLOCK_UNUSED))
-      {
-        StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
-
-        if (nextBlockIndex == BLOCK_UNUSED)
-        {
-          freeBlock = (depotIndex * blocksPerDepot) +
-                      (depotBlockOffset/sizeof(ULONG));
-        }
-
-        depotBlockOffset += sizeof(ULONG);
-      }
-
-      StorageImpl_ReleaseBigBlock(This, depotBuffer);
-    }
-
-    depotIndex++;
-    depotBlockOffset = 0;
-  }
-
-  This->prevFreeBlock = freeBlock;
-
-  return freeBlock;
-}
-
-/******************************************************************************
- *      Storage32Impl_AddBlockDepot
- *
- * This will create a depot block, essentially it is a block initialized
- * to BLOCK_UNUSEDs.
- */
-void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
-{
-  BYTE* blockBuffer;
-
-  blockBuffer = (BYTE *)StorageImpl_GetBigBlock(This, blockIndex);
-
-  /*
-   * Initialize blocks as free
-   */
-  memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
-
-  StorageImpl_ReleaseBigBlock(This, blockBuffer);
-}
-
-/******************************************************************************
- *      Storage32Impl_GetExtDepotBlock
- *
- * Returns the index of the block that corresponds to the specified depot
- * index. This method is only for depot indexes equal or greater than
- * COUNT_BBDEPOTINHEADER.
- */
-ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
-{
-  ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
-  ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
-  ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
-  ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
-  ULONG blockIndex             = BLOCK_UNUSED;
-  ULONG extBlockIndex          = This->extBigBlockDepotStart;
-
-  assert(depotIndex >= COUNT_BBDEPOTINHEADER);
-
-  if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
-    return BLOCK_UNUSED;
-
-  while (extBlockCount > 0)
-  {
-    extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
-    extBlockCount--;
-  }
-
-  if (extBlockIndex != BLOCK_UNUSED)
-  {
-    BYTE* depotBuffer;
-
-    depotBuffer = (BYTE *)StorageImpl_GetROBigBlock(This, extBlockIndex);
-
-    if (depotBuffer != 0)
-    {
-      StorageUtl_ReadDWord(depotBuffer,
-                           extBlockOffset * sizeof(ULONG),
-                           &blockIndex);
-
-      StorageImpl_ReleaseBigBlock(This, depotBuffer);
-    }
-  }
-
-  return blockIndex;
-}
-
-/******************************************************************************
- *      Storage32Impl_SetExtDepotBlock
- *
- * Associates the specified block index to the specified depot index.
- * This method is only for depot indexes equal or greater than
- * COUNT_BBDEPOTINHEADER.
- */
-void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
-                                    ULONG depotIndex,
-                                    ULONG blockIndex)
-{
-  ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
-  ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
-  ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
-  ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
-  ULONG extBlockIndex          = This->extBigBlockDepotStart;
-
-  assert(depotIndex >= COUNT_BBDEPOTINHEADER);
-
-  while (extBlockCount > 0)
-  {
-    extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
-    extBlockCount--;
-  }
-
-  if (extBlockIndex != BLOCK_UNUSED)
-  {
-    BYTE* depotBuffer;
-
-    depotBuffer = (BYTE *)StorageImpl_GetBigBlock(This, extBlockIndex);
-
-    if (depotBuffer != 0)
-    {
-      StorageUtl_WriteDWord(depotBuffer,
-                            extBlockOffset * sizeof(ULONG),
-                            blockIndex);
-
-      StorageImpl_ReleaseBigBlock(This, depotBuffer);
-    }
-  }
-}
-
-/******************************************************************************
- *      Storage32Impl_AddExtBlockDepot
- *
- * Creates an extended depot block.
- */
-ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
-{
-  ULONG numExtBlocks           = This->extBigBlockDepotCount;
-  ULONG nextExtBlock           = This->extBigBlockDepotStart;
-  BYTE* depotBuffer            = NULL;
-  ULONG index                  = BLOCK_UNUSED;
-  ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
-  ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
-  ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
-
-  index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
-          blocksPerDepotBlock;
-
-  if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
-  {
-    /*
-     * The first extended block.
-     */
-    This->extBigBlockDepotStart = index;
-  }
-  else
-  {
-    int i;
-    /*
-     * Follow the chain to the last one.
-     */
-    for (i = 0; i < (numExtBlocks - 1); i++)
-    {
-      nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
-    }
-
-    /*
-     * Add the new extended block to the chain.
-     */
-    depotBuffer = (BYTE *)StorageImpl_GetBigBlock(This, nextExtBlock);
-    StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
-    StorageImpl_ReleaseBigBlock(This, depotBuffer);
-  }
-
-  /*
-   * Initialize this block.
-   */
-  depotBuffer = (BYTE *)StorageImpl_GetBigBlock(This, index);
-  memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
-  StorageImpl_ReleaseBigBlock(This, depotBuffer);
-
-  return index;
-}
-
-/******************************************************************************
- *      Storage32Impl_FreeBigBlock
- *
- * This method will flag the specified block as free in the big block depot.
- */
-void  StorageImpl_FreeBigBlock(
-  StorageImpl* This,
-  ULONG          blockIndex)
-{
-  StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
-
-  if (blockIndex < This->prevFreeBlock)
-    This->prevFreeBlock = blockIndex;
-}
-
-/************************************************************************
- * Storage32Impl_GetNextBlockInChain
- *
- * This method will retrieve the block index of the next big block in
- * in the chain.
- *
- * Params:  This       - Pointer to the Storage object.
- *          blockIndex - Index of the block to retrieve the chain
- *                       for.
- *
- * Returns: This method returns the index of the next block in the chain.
- *          It will return the constants:
- *              BLOCK_SPECIAL - If the block given was not part of a
- *                              chain.
- *              BLOCK_END_OF_CHAIN - If the block given was the last in
- *                                   a chain.
- *              BLOCK_UNUSED - If the block given was not past of a chain
- *                             and is available.
- *              BLOCK_EXTBBDEPOT - This block is part of the extended
- *                                 big block depot.
- *
- * See Windows documentation for more details on IStorage methods.
- */
-ULONG StorageImpl_GetNextBlockInChain(
-  StorageImpl* This,
-  ULONG          blockIndex)
-{
-  ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
-  ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
-  ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
-  ULONG nextBlockIndex   = BLOCK_SPECIAL;
-  void* depotBuffer;
-  ULONG depotBlockIndexPos;
-
-  assert(depotBlockCount < This->bigBlockDepotCount);
-
-  /*
-   * Cache the currently accessed depot block.
-   */
-  if (depotBlockCount != This->indexBlockDepotCached)
-  {
-    This->indexBlockDepotCached = depotBlockCount;
-
-    if (depotBlockCount < COUNT_BBDEPOTINHEADER)
-    {
-      depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
-    }
-    else
-    {
-      /*
-       * We have to look in the extended depot.
-       */
-      depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
-    }
-
-    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
-
-    if (depotBuffer!=0)
-    {
-      StorageUtl_ReadDWords(depotBuffer, 0, This->blockDepotCached,
-			    NUM_BLOCKS_PER_DEPOT_BLOCK);
-
-      StorageImpl_ReleaseBigBlock(This, depotBuffer);
-    }
-  }
-
-  nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
-
-  return nextBlockIndex;
-}
-
-/******************************************************************************
- *      Storage32Impl_GetNextExtendedBlock
- *
- * Given an extended block this method will return the next extended block.
- *
- * NOTES:
- * The last ULONG of an extended block is the block index of the next
- * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
- * depot.
- *
- * Return values:
- *    - The index of the next extended block
- *    - BLOCK_UNUSED: there is no next extended block.
- *    - Any other return values denotes failure.
- */
-ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
-{
-  ULONG nextBlockIndex   = BLOCK_SPECIAL;
-  ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
-  void* depotBuffer;
-
-  depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
-
-  if (depotBuffer!=0)
-  {
-    StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
-
-    StorageImpl_ReleaseBigBlock(This, depotBuffer);
-  }
-
-  return nextBlockIndex;
-}
-
-/******************************************************************************
- *      Storage32Impl_SetNextBlockInChain
- *
- * This method will write the index of the specified block's next block
- * in the big block depot.
- *
- * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
- *              do the following
- *
- * Storage32Impl_SetNextBlockInChain(This, 3, 1);
- * Storage32Impl_SetNextBlockInChain(This, 1, 7);
- * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
- *
- */
-void  StorageImpl_SetNextBlockInChain(
-          StorageImpl* This,
-          ULONG          blockIndex,
-          ULONG          nextBlock)
-{
-  ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
-  ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
-  ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
-  ULONG depotBlockIndexPos;
-  void* depotBuffer;
-
-  assert(depotBlockCount < This->bigBlockDepotCount);
-  assert(blockIndex != nextBlock);
-
-  if (depotBlockCount < COUNT_BBDEPOTINHEADER)
-  {
-    depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
-  }
-  else
-  {
-    /*
-     * We have to look in the extended depot.
-     */
-    depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
-  }
-
-  depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
-
-  if (depotBuffer!=0)
-  {
-    StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
-    StorageImpl_ReleaseBigBlock(This, depotBuffer);
-  }
-
-  /*
-   * Update the cached block depot, if necessary.
-   */
-  if (depotBlockCount == This->indexBlockDepotCached)
-  {
-    This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
-  }
-}
-
-/******************************************************************************
- *      Storage32Impl_LoadFileHeader
- *
- * This method will read in the file header, i.e. big block index -1.
- */
-HRESULT StorageImpl_LoadFileHeader(
-          StorageImpl* This)
-{
-  HRESULT hr = STG_E_FILENOTFOUND;
-  void*   headerBigBlock = NULL;
-  int     index;
-
-  /*
-   * Get a pointer to the big block of data containing the header.
-   */
-  headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
-
-  /*
-   * Extract the information from the header.
-   */
-  if (headerBigBlock!=0)
-  {
-    /*
-     * Check for the "magic number" signature and return an error if it is not
-     * found.
-     */
-    if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
-    {
-      StorageImpl_ReleaseBigBlock(This, headerBigBlock);
-      return STG_E_OLDFORMAT;
-    }
-
-    if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
-    {
-      StorageImpl_ReleaseBigBlock(This, headerBigBlock);
-      return STG_E_INVALIDHEADER;
-    }
-
-    StorageUtl_ReadWord(
-      headerBigBlock, 
-      OFFSET_BIGBLOCKSIZEBITS,   
-      &This->bigBlockSizeBits);
-
-    StorageUtl_ReadWord(
-      headerBigBlock, 
-      OFFSET_SMALLBLOCKSIZEBITS, 
-      &This->smallBlockSizeBits);
-
-    StorageUtl_ReadDWord(
-      headerBigBlock, 
-      OFFSET_BBDEPOTCOUNT,      
-      &This->bigBlockDepotCount);
-
-    StorageUtl_ReadDWord(
-      headerBigBlock, 
-      OFFSET_ROOTSTARTBLOCK,    
-      &This->rootStartBlock);
-
-    StorageUtl_ReadDWord(
-      headerBigBlock, 
-      OFFSET_SBDEPOTSTART,      
-      &This->smallBlockDepotStart);
-
-    StorageUtl_ReadDWord( 
-      headerBigBlock, 
-      OFFSET_EXTBBDEPOTSTART,   
-      &This->extBigBlockDepotStart);
-
-    StorageUtl_ReadDWord(
-      headerBigBlock, 
-      OFFSET_EXTBBDEPOTCOUNT,   
-      &This->extBigBlockDepotCount);
-    
-    for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
-    {
-      StorageUtl_ReadDWord(
-        headerBigBlock, 
-        OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
-        &(This->bigBlockDepotStart[index]));
-    }
-    
-    /*
-     * Make the bitwise arithmetic to get the size of the blocks in bytes.
-     */
-    if ((1 << 2) == 4)
-    {
-      This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
-      This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
-    }
-    else
-    {
-      This->bigBlockSize   = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
-      This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
-    }
-    
-    /*
-     * Right now, the code is making some assumptions about the size of the 
-     * blocks, just make sure they are what we're expecting.
-     */
-    assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) && 
-            (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
-    
-    /*
-     * Release the block.
-     */
-    StorageImpl_ReleaseBigBlock(This, headerBigBlock);
-
-    hr = S_OK;
-  }
-  
-  return hr;
-}
-
-/******************************************************************************
- *      Storage32Impl_SaveFileHeader
- *
- * This method will save to the file the header, i.e. big block -1.
- */
-void StorageImpl_SaveFileHeader(
-          StorageImpl* This)
-{
-  BYTE   headerBigBlock[BIG_BLOCK_SIZE];
-  int    index;
-  BOOL success;
-
-  /*
-   * Get a pointer to the big block of data containing the header.
-   */
-  success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
-  
-  /*
-   * If the block read failed, the file is probably new.
-   */
-  if (!success)
-  {
-    /*
-     * Initialize for all unknown fields.
-     */
-    memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
-    
-    /*
-     * Initialize the magic number.
-     */
-    memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
-    
-    /*
-     * And a bunch of things we don't know what they mean
-     */
-    StorageUtl_WriteWord(headerBigBlock,  0x18, 0x3b);
-    StorageUtl_WriteWord(headerBigBlock,  0x1a, 0x3);
-    StorageUtl_WriteWord(headerBigBlock,  0x1c, (WORD)-2);
-    StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
-    StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
-  }
-  
-  /*
-   * Write the information to the header.
-   */
-  if (headerBigBlock!=0)
-  {
-    StorageUtl_WriteWord(
-      headerBigBlock, 
-      OFFSET_BIGBLOCKSIZEBITS,   
-      This->bigBlockSizeBits);
-
-    StorageUtl_WriteWord(
-      headerBigBlock, 
-      OFFSET_SMALLBLOCKSIZEBITS, 
-      This->smallBlockSizeBits);
-
-    StorageUtl_WriteDWord(
-      headerBigBlock, 
-      OFFSET_BBDEPOTCOUNT,      
-      This->bigBlockDepotCount);
-
-    StorageUtl_WriteDWord(
-      headerBigBlock, 
-      OFFSET_ROOTSTARTBLOCK,    
-      This->rootStartBlock);
-
-    StorageUtl_WriteDWord(
-      headerBigBlock, 
-      OFFSET_SBDEPOTSTART,      
-      This->smallBlockDepotStart);
-
-    StorageUtl_WriteDWord(
-      headerBigBlock, 
-      OFFSET_EXTBBDEPOTSTART,   
-      This->extBigBlockDepotStart);
-
-    StorageUtl_WriteDWord(
-      headerBigBlock, 
-      OFFSET_EXTBBDEPOTCOUNT,   
-      This->extBigBlockDepotCount);
-
-    for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
-    {
-      StorageUtl_WriteDWord(
-        headerBigBlock, 
-        OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
-        (This->bigBlockDepotStart[index]));
-    }
-  }
-  
-  /*
-   * Write the big block back to the file.
-   */
-  StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
-}
-
-/******************************************************************************
- *      Storage32Impl_ReadProperty
- *
- * This method will read the specified property from the property chain.
- */
-BOOL StorageImpl_ReadProperty(
-  StorageImpl* This,
-  ULONG          index,
-  StgProperty*   buffer)
-{
-  BYTE           currentProperty[PROPSET_BLOCK_SIZE];
-  ULARGE_INTEGER offsetInPropSet;
-  BOOL         readSucessful;
-  ULONG          bytesRead;
-
-  offsetInPropSet.HighPart = 0;
-  offsetInPropSet.LowPart  = index * PROPSET_BLOCK_SIZE;
-  
-  readSucessful = BlockChainStream_ReadAt(
-                    This->rootBlockChain,
-                    offsetInPropSet,
-                    PROPSET_BLOCK_SIZE,
-                    currentProperty,
-                    &bytesRead);
-  
-  if (readSucessful)
-  {
-    memset(buffer->name, 0, sizeof(buffer->name));
-    memcpy(
-      buffer->name, 
-      currentProperty+OFFSET_PS_NAME, 
-      PROPERTY_NAME_BUFFER_LEN );
-
-    memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
-    
-    StorageUtl_ReadWord(
-      currentProperty,  
-      OFFSET_PS_NAMELENGTH,  
-      &buffer->sizeOfNameString);
-
-    StorageUtl_ReadDWord(
-      currentProperty, 
-      OFFSET_PS_PREVIOUSPROP, 
-      &buffer->previousProperty);
-
-    StorageUtl_ReadDWord(
-      currentProperty, 
-      OFFSET_PS_NEXTPROP,     
-      &buffer->nextProperty);
-
-    StorageUtl_ReadDWord(
-      currentProperty, 
-      OFFSET_PS_DIRPROP,      
-      &buffer->dirProperty);
-
-    StorageUtl_ReadGUID(
-      currentProperty,  
-      OFFSET_PS_GUID,        
-      &buffer->propertyUniqueID);
-
-    StorageUtl_ReadDWord(
-      currentProperty, 
-      OFFSET_PS_TSS1,         
-      &buffer->timeStampS1);
-
-    StorageUtl_ReadDWord(
-      currentProperty, 
-      OFFSET_PS_TSD1,         
-      &buffer->timeStampD1);
-
-    StorageUtl_ReadDWord(
-      currentProperty, 
-      OFFSET_PS_TSS2,         
-      &buffer->timeStampS2);
-
-    StorageUtl_ReadDWord(
-      currentProperty, 
-      OFFSET_PS_TSD2,         
-      &buffer->timeStampD2);
-
-    StorageUtl_ReadDWord(
-      currentProperty, 
-      OFFSET_PS_STARTBLOCK,   
-      &buffer->startingBlock);
-
-    StorageUtl_ReadDWord(
-      currentProperty, 
-      OFFSET_PS_SIZE,         
-      &buffer->size.LowPart);
-
-    buffer->size.HighPart = 0;
-  }
-
-  return readSucessful;
-}
-
-/*********************************************************************
- * Write the specified property into the property chain
- */
-BOOL StorageImpl_WriteProperty(
-  StorageImpl* This,
-  ULONG          index,
-  StgProperty*   buffer)
-{
-  BYTE           currentProperty[PROPSET_BLOCK_SIZE];
-  ULARGE_INTEGER offsetInPropSet;
-  BOOL         writeSucessful;
-  ULONG          bytesWritten;
-
-  offsetInPropSet.HighPart = 0;
-  offsetInPropSet.LowPart  = index * PROPSET_BLOCK_SIZE;
-
-  memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
-
-  memcpy(
-    currentProperty + OFFSET_PS_NAME, 
-    buffer->name, 
-    PROPERTY_NAME_BUFFER_LEN );
-
-  memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
-
-  StorageUtl_WriteWord(
-    currentProperty,  
-      OFFSET_PS_NAMELENGTH,   
-      buffer->sizeOfNameString);
-
-  StorageUtl_WriteDWord(
-    currentProperty, 
-      OFFSET_PS_PREVIOUSPROP, 
-      buffer->previousProperty);
-
-  StorageUtl_WriteDWord(
-    currentProperty, 
-      OFFSET_PS_NEXTPROP,     
-      buffer->nextProperty);
-
-  StorageUtl_WriteDWord(
-    currentProperty, 
-      OFFSET_PS_DIRPROP,      
-      buffer->dirProperty);
-
-  StorageUtl_WriteGUID(
-    currentProperty,  
-      OFFSET_PS_GUID,        
-      &buffer->propertyUniqueID);
-
-  StorageUtl_WriteDWord(
-    currentProperty, 
-      OFFSET_PS_TSS1,         
-      buffer->timeStampS1);
-
-  StorageUtl_WriteDWord(
-    currentProperty, 
-      OFFSET_PS_TSD1,         
-      buffer->timeStampD1);
-
-  StorageUtl_WriteDWord(
-    currentProperty, 
-      OFFSET_PS_TSS2,         
-      buffer->timeStampS2);
-
-  StorageUtl_WriteDWord(
-    currentProperty, 
-      OFFSET_PS_TSD2,         
-      buffer->timeStampD2);
-
-  StorageUtl_WriteDWord(
-    currentProperty, 
-      OFFSET_PS_STARTBLOCK,   
-      buffer->startingBlock);
-
-  StorageUtl_WriteDWord(
-    currentProperty, 
-      OFFSET_PS_SIZE,         
-      buffer->size.LowPart);
-
-  writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
-                                            offsetInPropSet,
-                                            PROPSET_BLOCK_SIZE,
-                                            currentProperty,
-                                            &bytesWritten);
-  return writeSucessful;
-}
-
-BOOL StorageImpl_ReadBigBlock(
-  StorageImpl* This,
-  ULONG          blockIndex,
-  void*          buffer)
-{
-  void* bigBlockBuffer;
-
-  bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
-
-  if (bigBlockBuffer!=0)
-  {
-    memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
-
-    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
-
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-BOOL StorageImpl_WriteBigBlock(
-  StorageImpl* This,
-  ULONG          blockIndex,
-  void*          buffer)
-{
-  void* bigBlockBuffer;
-
-  bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
-
-  if (bigBlockBuffer!=0)
-  {
-    memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
-
-    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
-    
-    return TRUE;
-  }
-  
-  return FALSE;
-}
-
-void* StorageImpl_GetROBigBlock(
-  StorageImpl* This,
-  ULONG          blockIndex)
-{
-  return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
-}
-
-void* StorageImpl_GetBigBlock(
-  StorageImpl* This,
-  ULONG          blockIndex)
-{
-  return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
-}
-
-void StorageImpl_ReleaseBigBlock(
-  StorageImpl* This,
-  void*          pBigBlock)
-{
-  BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
-}
-
-/******************************************************************************
- *              Storage32Impl_SmallBlocksToBigBlocks
- *
- * This method will convert a small block chain to a big block chain.
- * The small block chain will be destroyed.
- */
-BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
-                      StorageImpl* This,
-                      SmallBlockChainStream** ppsbChain)
-{
-  ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
-  ULARGE_INTEGER size, offset;
-  ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
-  ULONG propertyIndex;
-  BOOL successRead, successWrite;
-  StgProperty chainProperty;
-  BYTE *buffer;
-  BlockChainStream *bbTempChain = NULL;
-  BlockChainStream *bigBlockChain = NULL;
-
-  /*
-   * Create a temporary big block chain that doesn't have
-   * an associated property. This temporary chain will be
-   * used to copy data from small blocks to big blocks.
-   */
-  bbTempChain = BlockChainStream_Construct(This,
-                                           &bbHeadOfChain,
-                                           PROPERTY_NULL);
-
-  /*
-   * Grow the big block chain.
-   */
-  size = SmallBlockChainStream_GetSize(*ppsbChain);
-  BlockChainStream_SetSize(bbTempChain, size);
-
-  /*
-   * Copy the contents of the small block chain to the big block chain
-   * by small block size increments.
-   */
-  offset.LowPart = 0;
-  offset.HighPart = 0;
-  cbTotalRead = 0;
-  cbTotalWritten = 0;
-
-  buffer = (BYTE *) malloc(DEF_SMALL_BLOCK_SIZE);
-  do
-  {
-    successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
-                                               offset,
-                                               DEF_SMALL_BLOCK_SIZE,
-                                               buffer,
-                                               &cbRead);
-    cbTotalRead += cbRead;
-
-    successWrite = BlockChainStream_WriteAt(bbTempChain,
-                                            offset,
-                                            cbRead,
-                                            buffer,
-                                            &cbWritten);
-    cbTotalWritten += cbWritten;
-
-    offset.LowPart += This->smallBlockSize;
-
-  } while (successRead && successWrite);
-  free(buffer);
-
-  assert(cbTotalRead == cbTotalWritten);
-
-  /*
-   * Destroy the small block chain.
-   */
-  propertyIndex = (*ppsbChain)->ownerPropertyIndex;
-  size.HighPart = 0;
-  size.LowPart  = 0;
-  SmallBlockChainStream_SetSize(*ppsbChain, size);
-  SmallBlockChainStream_Destroy(*ppsbChain);
-  *ppsbChain = 0;
-
-  /*
-   * Change the property information. This chain is now a big block chain
-   * and it doesn't reside in the small blocks chain anymore.
-   */
-  StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
-
-  chainProperty.startingBlock = bbHeadOfChain;
-
-  StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
-
-  /*
-   * Destroy the temporary propertyless big block chain.
-   * Create a new big block chain associated with this property.
-   */
-  BlockChainStream_Destroy(bbTempChain);
-  bigBlockChain = BlockChainStream_Construct(This,
-                                             NULL,
-                                             propertyIndex);
-
-  return bigBlockChain;
-}
-
-/******************************************************************************
-** Storage32InternalImpl implementation
-*/
-
-StorageInternalImpl* StorageInternalImpl_Construct(
-  StorageImpl* ancestorStorage,  
-  ULONG          rootPropertyIndex)
-{
-  StorageInternalImpl* newStorage;
-
-  /*
-   * Allocate space for the new storage object
-   */
-  newStorage = (StorageInternalImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
-
-  if (newStorage!=0)
-  {
-    memset(newStorage, 0, sizeof(StorageInternalImpl));
-
-    /*
-     * Initialize the virtual function table.
-     */
-    ICOM_VTBL(newStorage)    = &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;
-
-    return newStorage;
-  }
-
-  return 0;
-}
-
-void StorageInternalImpl_Destroy(
-  StorageInternalImpl* This)
-{
-  StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
-  HeapFree(GetProcessHeap(), 0, This);
-}
-
-/******************************************************************************
-**
-** Storage32InternalImpl_Commit
-**
-** The non-root storages cannot be opened in transacted mode thus this function
-** does nothing.
-*/
-HRESULT WINAPI StorageInternalImpl_Commit( 
-  IStorage*            iface,
-  DWORD                  grfCommitFlags)  /* [in] */ 
-{
-  return S_OK;
-}
-        
-/******************************************************************************
-**
-** Storage32InternalImpl_Revert
-**
-** The non-root storages cannot be opened in transacted mode thus this function
-** does nothing.
-*/
-HRESULT WINAPI StorageInternalImpl_Revert( 
-  IStorage*            iface)
-{
-  return S_OK;
-}
-
-/******************************************************************************
-** IEnumSTATSTGImpl implementation
-*/
-
-IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
-  StorageImpl* parentStorage,
-  ULONG          firstPropertyNode)
-{
-  IEnumSTATSTGImpl* newEnumeration;
-
-  newEnumeration = (IEnumSTATSTGImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
-  
-  if (newEnumeration!=0)
-  {
-    /*
-     * Set-up the virtual function table and reference count.
-     */
-    ICOM_VTBL(newEnumeration) = &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 = 
-      (ULONG *)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)
-{
-  IStorage_Release((IStorage*)This->parentStorage);
-  HeapFree(GetProcessHeap(), 0, This->stackToVisit);
-  HeapFree(GetProcessHeap(), 0, This);
-}
-
-HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
-  IEnumSTATSTG*     iface,
-  REFIID            riid,
-  void**            ppvObject)
-{
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
-
-  /*
-   * Perform a sanity check on the parameters.
-   */
-  if (ppvObject==0)
-    return E_INVALIDARG;
-
-  /*
-   * Initialize the return parameter.
-   */
-  *ppvObject = 0;
-
-  /*
-   * Compare the riid with the interface IDs implemented by this object.
-   */
-  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
-  {
-    *ppvObject = (IEnumSTATSTG*)This;
-  }
-  else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0) 
-  {
-    *ppvObject = (IEnumSTATSTG*)This;
-  }
-
-  /*
-   * 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;
-}
-        
-ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
-  IEnumSTATSTG* iface)
-{
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
-
-  This->ref++;
-  return This->ref;
-}
-        
-ULONG   WINAPI IEnumSTATSTGImpl_Release(
-  IEnumSTATSTG* iface)
-{
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
-
-  ULONG newRef;
-
-  This->ref--;
-  newRef = This->ref;
-
-  /*
-   * If the reference count goes down to 0, perform suicide.
-   */
-  if (newRef==0)
-  {
-    IEnumSTATSTGImpl_Destroy(This);
-  }
-
-  return newRef;;
-}
-
-HRESULT WINAPI IEnumSTATSTGImpl_Next(
-  IEnumSTATSTG* iface,
-  ULONG             celt,
-  STATSTG*          rgelt,
-  ULONG*            pceltFetched)
-{
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
-
-  StgProperty currentProperty;
-  STATSTG*    currentReturnStruct = rgelt;
-  ULONG       objectFetched       = 0;
-  ULONG      currentSearchNode;
-
-  /*
-   * Perform a sanity check on the parameters.
-   */
-  if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
-    return E_INVALIDARG;  
-  
-  /*
-   * To avoid the special case, get another pointer to a ULONG value if
-   * the caller didn't supply one.
-   */
-  if (pceltFetched==0)
-    pceltFetched = &objectFetched;
-  
-  /*
-   * Start the iteration, we will iterate until we hit the end of the
-   * linked list or until we hit the number of items to iterate through
-   */
-  *pceltFetched = 0;
-
-  /*
-   * Start with the node at the top of the stack.
-   */
-  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
-
-  while ( ( *pceltFetched < celt) && 
-          ( currentSearchNode!=PROPERTY_NULL) )
-  {
-    /* 
-     * Remove the top node from the stack
-     */
-    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
-
-    /*
-     * Read the property from the storage.
-     */
-    StorageImpl_ReadProperty(This->parentStorage,
-      currentSearchNode, 
-      &currentProperty);
-
-    /*
-     * Copy the information to the return buffer.
-     */
-    StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
-      &currentProperty,
-      STATFLAG_DEFAULT);
-        
-    /*
-     * Step to the next item in the iteration
-     */
-    (*pceltFetched)++;
-    currentReturnStruct++;
-
-    /*
-     * Push the next search node in the search stack.
-     */
-    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
-
-    /*
-     * continue the iteration.
-     */
-    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
-  }
-
-  if (*pceltFetched == celt)
-    return S_OK;
-
-  return S_FALSE;
-}
-
-        
-HRESULT WINAPI IEnumSTATSTGImpl_Skip(
-  IEnumSTATSTG* iface,
-  ULONG             celt)
-{
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
-
-  StgProperty currentProperty;
-  ULONG       objectFetched       = 0;
-  ULONG       currentSearchNode;
-
-  /*
-   * Start with the node at the top of the stack.
-   */
-  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
-
-  while ( (objectFetched < celt) && 
-          (currentSearchNode!=PROPERTY_NULL) )
-  {
-    /* 
-     * Remove the top node from the stack
-     */
-    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
-
-    /*
-     * Read the property from the storage.
-     */
-    StorageImpl_ReadProperty(This->parentStorage,
-      currentSearchNode, 
-      &currentProperty);
-    
-    /*
-     * Step to the next item in the iteration
-     */
-    objectFetched++;
-
-    /*
-     * Push the next search node in the search stack.
-     */
-    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
-
-    /*
-     * continue the iteration.
-     */
-    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
-  }
-
-  if (objectFetched == celt)
-    return S_OK;
-
-  return S_FALSE;
-}
-        
-HRESULT WINAPI IEnumSTATSTGImpl_Reset(
-  IEnumSTATSTG* iface)
-{
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
-
-  StgProperty rootProperty;
-  BOOL      readSucessful;
-
-  /*
-   * Re-initialize the search stack to an empty stack
-   */
-  This->stackSize = 0;
-
-  /*
-   * Read the root property from the storage.
-   */
-  readSucessful = StorageImpl_ReadProperty(
-                    This->parentStorage,
-                    This->firstPropertyNode, 
-                    &rootProperty);
-
-  if (readSucessful)
-  {
-    assert(rootProperty.sizeOfNameString!=0);
-
-    /*
-     * Push the search node in the search stack.
-     */
-    IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
-  }
-
-  return S_OK;
-}
-        
-HRESULT WINAPI IEnumSTATSTGImpl_Clone(
-  IEnumSTATSTG* iface,
-  IEnumSTATSTG**    ppenum)
-{
-  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
-
-  IEnumSTATSTGImpl* newClone;
-
-  /*
-   * Perform a sanity check on the parameters.
-   */
-  if (ppenum==0)
-    return E_INVALIDARG;
-  
-  newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
-               This->firstPropertyNode);
-
-  
-  /*
-   * The new clone enumeration must point to the same current node as
-   * the ole one.
-   */
-  newClone->stackSize    = This->stackSize    ;
-  newClone->stackMaxSize = This->stackMaxSize ;
-  newClone->stackToVisit = 
-    (ULONG *)HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
-
-  memcpy(
-    newClone->stackToVisit, 
-    This->stackToVisit, 
-    sizeof(ULONG) * newClone->stackSize);
-
-  *ppenum = (IEnumSTATSTG*)newClone;
-
-  /*
-   * Don't forget to nail down a reference to the clone before
-   * returning it.
-   */
-  IEnumSTATSTGImpl_AddRef(*ppenum);
-
-  return S_OK;
-}
-
-INT IEnumSTATSTGImpl_FindParentProperty(
-  IEnumSTATSTGImpl *This,
-  ULONG             childProperty, 
-  StgProperty      *currentProperty,
-  ULONG            *thisNodeId)
-{
-  ULONG currentSearchNode;
-  ULONG foundNode;
-
-  /*
-   * To avoid the special case, get another pointer to a ULONG value if
-   * the caller didn't supply one.
-   */
-  if (thisNodeId==0)
-    thisNodeId = &foundNode;
-
-  /*
-   * Start with the node at the top of the stack.
-   */
-  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
-  
-
-  while (currentSearchNode!=PROPERTY_NULL)
-  {
-    /*
-     * Store the current node in the returned parameters
-     */
-    *thisNodeId = currentSearchNode;
-
-    /* 
-     * Remove the top node from the stack
-     */
-    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
-
-    /*
-     * Read the property from the storage.
-     */
-    StorageImpl_ReadProperty(
-      This->parentStorage,
-      currentSearchNode, 
-      currentProperty);
-      
-    if (currentProperty->previousProperty == childProperty)
-      return PROPERTY_RELATION_PREVIOUS;
-
-    else if (currentProperty->nextProperty == childProperty)  
-      return PROPERTY_RELATION_NEXT;
-  
-    else if (currentProperty->dirProperty == childProperty)
-      return PROPERTY_RELATION_DIR;
-       
-    /*
-     * Push the next search node in the search stack.
-     */
-    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
-
-    /*
-     * continue the iteration.
-     */
-    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
-  }
-
-  return PROPERTY_NULL;
-}
-
-ULONG IEnumSTATSTGImpl_FindProperty(
-  IEnumSTATSTGImpl* This,
-  const OLECHAR*  lpszPropName,
-  StgProperty*      currentProperty)
-{
-  ULONG currentSearchNode;
-
-  /*
-   * Start with the node at the top of the stack.
-   */
-  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
-
-  while (currentSearchNode!=PROPERTY_NULL)
-  {
-    /* 
-     * Remove the top node from the stack
-     */
-    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
-
-    /*
-     * Read the property from the storage.
-     */
-    StorageImpl_ReadProperty(This->parentStorage,
-      currentSearchNode, 
-      currentProperty);
-
-    if ( propertyNameCmp(
-          (OLECHAR*)currentProperty->name, 
-          (OLECHAR*)lpszPropName) == 0)
-      return currentSearchNode;
-
-    /*
-     * Push the next search node in the search stack.
-     */
-    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
-
-    /*
-     * continue the iteration.
-     */
-    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
-  }
-
-  return PROPERTY_NULL;
-}
-
-void IEnumSTATSTGImpl_PushSearchNode(
-  IEnumSTATSTGImpl* This,
-  ULONG             nodeToPush)
-{
-  StgProperty rootProperty;
-  BOOL      readSucessful;
-
-  /*
-   * First, make sure we're not trying to push an unexisting node.
-   */
-  if (nodeToPush==PROPERTY_NULL)
-    return;
-
-  /*
-   * First push the node to the stack
-   */
-  if (This->stackSize == This->stackMaxSize)
-  {
-    This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
-
-    This->stackToVisit = (ULONG *)HeapReAlloc(
-                           GetProcessHeap(), 
-                           0,
-                           This->stackToVisit,
-                           sizeof(ULONG) * This->stackMaxSize);
-  }
-
-  This->stackToVisit[This->stackSize] = nodeToPush;
-  This->stackSize++;
-
-  /*
-   * Read the root property from the storage.
-   */
-  readSucessful = StorageImpl_ReadProperty(
-                    This->parentStorage,
-                    nodeToPush, 
-                    &rootProperty);
-
-  if (readSucessful)
-  {
-    assert(rootProperty.sizeOfNameString!=0);
-
-    /*
-     * Push the previous search node in the search stack.
-     */
-    IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
-  }
-}
-
-ULONG IEnumSTATSTGImpl_PopSearchNode(
-  IEnumSTATSTGImpl* This,
-  BOOL            remove)
-{
-  ULONG topNode;
-
-  if (This->stackSize == 0)
-    return PROPERTY_NULL;
-
-  topNode = This->stackToVisit[This->stackSize-1];
-
-  if (remove)
-    This->stackSize--;
-
-  return topNode;
-}
-
-/******************************************************************************
-** StorageUtl implementation
-*/
-
-void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
-{
-  memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
-}
-
-void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
-{
-  memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
-}
-
-void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
-{
-  memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
-}
-
-void StorageUtl_ReadDWords(void *buffer, ULONG offset, DWORD *values,
-			   ULONG len)
-{
-  memcpy(values, (BYTE*)buffer+offset, sizeof(DWORD)*len);
-}
-
-void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
-{
-  memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
-}
-
-void StorageUtl_ReadGUID(void* 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));
-}
-
-void StorageUtl_WriteGUID(void* buffer, ULONG offset, 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));
-}
-
-void StorageUtl_CopyPropertyToSTATSTG(
-  STATSTG*     destination,
-  StgProperty* source,
-  int          statFlags)
-{
-  /*
-   * The copy of the string occurs only when the flag is not set
-   */
-  if ((statFlags & STATFLAG_NONAME) != 0)
-  {
-    destination->pwcsName = 0;
-  }
-  else
-  {
-    destination->pwcsName = 
-      (WCHAR *)CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
-
-    lstrcpyW((LPWSTR)destination->pwcsName, source->name);
-  }
-  
-  switch (source->propertyType)
-  {
-    case PROPTYPE_STORAGE:
-    case PROPTYPE_ROOT:
-      destination->type = STGTY_STORAGE;
-      break;
-    case PROPTYPE_STREAM:
-      destination->type = STGTY_STREAM;
-      break;
-    default:
-      destination->type = STGTY_STREAM;
-      break;        
-  }
-
-  destination->cbSize            = source->size;
-/*    
-  currentReturnStruct->mtime     = {0}; TODO
-  currentReturnStruct->ctime     = {0};
-  currentReturnStruct->atime     = {0}; 
-*/
-  destination->grfMode           = 0;
-  destination->grfLocksSupported = 0; 
-  destination->clsid             = source->propertyUniqueID;
-  destination->grfStateBits      = 0; 
-  destination->reserved          = 0; 
-}
-
-/******************************************************************************
-** BlockChainStream implementation
-*/
-
-BlockChainStream* BlockChainStream_Construct(
-  StorageImpl* parentStorage,  
-  ULONG*         headOfStreamPlaceHolder,
-  ULONG          propertyIndex)
-{
-  BlockChainStream* newStream;
-
-  newStream = (BlockChainStream *)HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
-
-  newStream->parentStorage           = parentStorage;
-  newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
-  newStream->ownerPropertyIndex      = propertyIndex;
-  newStream->lastBlockNoInSequence   = 0xFFFFFFFF;
-  newStream->lazyInitComplete        = FALSE;
-  newStream->tailIndex               = BLOCK_END_OF_CHAIN;
-  newStream->numBlocks               = 0;
-
-  return newStream;
-}
-
-static void BlockChainStream_LazyInit(BlockChainStream *This)
-{
-    ULONG numBlocks = 0;
-    ULONG tailIndex = BLOCK_END_OF_CHAIN;
-    StorageImpl *parentStorage = This->parentStorage;
-
-    ULONG blockIndex = BlockChainStream_GetHeadOfChain(This);
-
-    while (blockIndex != BLOCK_END_OF_CHAIN)
-    {
-	numBlocks++;
-	tailIndex = blockIndex;
-
-	blockIndex = StorageImpl_GetNextBlockInChain(parentStorage,
-						     blockIndex);
-    }
-
-    This->numBlocks = numBlocks;
-    This->tailIndex = tailIndex;
-}
-
-static inline ULONG BlockChainStream_TailIndex(BlockChainStream *This)
-{
-    if (!This->lazyInitComplete)
-	BlockChainStream_LazyInit(This);
-    return This->tailIndex;
-}
-
-static inline ULONG BlockChainStream_NumBlocks(BlockChainStream *This)
-{
-    if (!This->lazyInitComplete)
-	BlockChainStream_LazyInit(This);
-    return This->numBlocks;
-}
-
-void BlockChainStream_Destroy(BlockChainStream* This)
-{
-  HeapFree(GetProcessHeap(), 0, This);
-}
-
-/******************************************************************************
- *      BlockChainStream_GetHeadOfChain
- *
- * Returns the head of this stream chain.
- * Some special chains don't have properties, their heads are kept in
- * This->headOfStreamPlaceHolder.
- *
- */
-ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
-{
-  StgProperty chainProperty;
-  BOOL      readSucessful;
-
-  if (This->headOfStreamPlaceHolder != 0)
-    return *(This->headOfStreamPlaceHolder);
-
-  if (This->ownerPropertyIndex != PROPERTY_NULL)
-  {
-    readSucessful = StorageImpl_ReadProperty(
-                      This->parentStorage,
-                      This->ownerPropertyIndex,
-                      &chainProperty);
-
-    if (readSucessful)
-    {
-      return chainProperty.startingBlock;
-    }
-  }
-
-  return BLOCK_END_OF_CHAIN;
-}
-
-/******************************************************************************
- *       BlockChainStream_GetCount
- *
- * Returns the number of blocks that comprises this chain.
- * This is not the size of the stream as the last block may not be full!
- * 
- */
-ULONG BlockChainStream_GetCount(BlockChainStream* This)
-{
-  ULONG blockIndex;
-  ULONG count = 0;
-
-  blockIndex = BlockChainStream_GetHeadOfChain(This);
-
-  while (blockIndex != BLOCK_END_OF_CHAIN)
-  {
-    count++;
-
-    blockIndex = StorageImpl_GetNextBlockInChain(
-                   This->parentStorage, 
-                   blockIndex);
-  }
-
-  return count;
-}
-
-/******************************************************************************
- *      BlockChainStream_ReadAt 
- *
- * Reads a specified number of bytes from this chain at the specified offset.
- * bytesRead may be NULL.
- * Failure will be returned if the specified number of bytes has not been read.
- */
-BOOL BlockChainStream_ReadAt(BlockChainStream* This,
-  ULARGE_INTEGER offset,
-  ULONG          size,
-  void*          buffer,
-  ULONG*         bytesRead)
-{
-  ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
-  ULONG offsetInBlock     = offset.LowPart % This->parentStorage->bigBlockSize;
-  ULONG bytesToReadInBuffer;
-  ULONG blockIndex;
-  BYTE* bufferWalker;
-  BYTE* bigBlockBuffer;
-
-  /*
-   * Find the first block in the stream that contains part of the buffer.
-   */
-  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
-       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
-       (blockNoInSequence < This->lastBlockNoInSequence) )
-  {
-    blockIndex = BlockChainStream_GetHeadOfChain(This);
-    This->lastBlockNoInSequence = blockNoInSequence;
-  }
-  else
-  {
-    ULONG temp = blockNoInSequence;
-
-    blockIndex = This->lastBlockNoInSequenceIndex;
-    blockNoInSequence -= This->lastBlockNoInSequence;
-    This->lastBlockNoInSequence = temp;
-  }
-
-  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
-  {
-    blockIndex = 
-      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
-    
-    blockNoInSequence--;
-  }
-
-  This->lastBlockNoInSequenceIndex = blockIndex;
-
-  /*
-   * Start reading the buffer.
-   */
-  *bytesRead   = 0;
-  bufferWalker = (BYTE *)buffer;
-  
-  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
-  {
-    /*
-     * Calculate how many bytes we can copy from this big block.
-     */
-    bytesToReadInBuffer = 
-      MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
-    
-    /*
-     * Copy those bytes to the buffer
-     */
-    bigBlockBuffer = 
-      (BYTE *)StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
-    
-    memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
-    
-    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
-    
-    /*
-     * Step to the next big block.
-     */
-    blockIndex    = 
-      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
-
-    bufferWalker += bytesToReadInBuffer;
-    size         -= bytesToReadInBuffer;
-    *bytesRead   += bytesToReadInBuffer;
-    offsetInBlock = 0;  /* There is no offset on the next block */
-
-  }
-  
-  return (size == 0);
-}
-
-/******************************************************************************
- *      BlockChainStream_WriteAt
- *
- * Writes the specified number of bytes to this chain at the specified offset.
- * bytesWritten may be NULL.
- * Will fail if not all specified number of bytes have been written.
- */
-BOOL BlockChainStream_WriteAt(BlockChainStream* This,
-  ULARGE_INTEGER    offset,
-  ULONG             size,
-  const void*       buffer,
-  ULONG*            bytesWritten)
-{
-  ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
-  ULONG offsetInBlock     = offset.LowPart % This->parentStorage->bigBlockSize;
-  ULONG bytesToWrite;
-  ULONG blockIndex;
-  BYTE* bufferWalker;
-  BYTE* bigBlockBuffer;
-
-  /*
-   * Find the first block in the stream that contains part of the buffer.
-   */
-  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
-       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
-       (blockNoInSequence < This->lastBlockNoInSequence) )
-  {
-    blockIndex = BlockChainStream_GetHeadOfChain(This);
-    This->lastBlockNoInSequence = blockNoInSequence;
-  }
-  else
-  {
-    ULONG temp = blockNoInSequence;
-
-    blockIndex = This->lastBlockNoInSequenceIndex;
-    blockNoInSequence -= This->lastBlockNoInSequence;
-    This->lastBlockNoInSequence = temp;
-  }
-
-  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
-  {
-    blockIndex = 
-      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
-    
-    blockNoInSequence--;
-  }
-
-  This->lastBlockNoInSequenceIndex = blockIndex;
-
-  /*
-   * Here, I'm casting away the constness on the buffer variable
-   * This is OK since we don't intend to modify that buffer.
-   */
-  *bytesWritten   = 0;
-  bufferWalker = (BYTE*)buffer;
-
-  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
-  {
-    /*
-     * Calculate how many bytes we can copy from this big block.
-     */
-    bytesToWrite = 
-      MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
-    
-    /*
-     * Copy those bytes to the buffer
-     */
-    bigBlockBuffer = (BYTE *)StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
-    
-    memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
-    
-    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
-    
-    /*
-     * Step to the next big block.
-     */
-    blockIndex    = 
-      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
-
-    bufferWalker  += bytesToWrite;
-    size          -= bytesToWrite;
-    *bytesWritten += bytesToWrite;
-    offsetInBlock  = 0;      /* There is no offset on the next block */
-  }
-  
-  return (size == 0);
-}
-
-/******************************************************************************
- *      BlockChainStream_Shrink
- *
- * Shrinks this chain in the big block depot.
- */
-BOOL BlockChainStream_Shrink(BlockChainStream* This,
-                               ULARGE_INTEGER    newSize)
-{
-  ULONG blockIndex, extraBlock;
-  ULONG numBlocks;
-  ULONG count = 1;
-
-  /*
-   * Reset the last accessed block cache.
-   */
-  This->lastBlockNoInSequence = 0xFFFFFFFF;
-  This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
-
-  /*
-   * Figure out how many blocks are needed to contain the new size
-   */
-  numBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
-
-  if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
-    numBlocks++;
-
-  blockIndex = BlockChainStream_GetHeadOfChain(This);
-
-  /*
-   * Go to the new end of chain
-   */
-  while (count < numBlocks)
-  {
-    blockIndex = 
-      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
-
-    count++;
-  }
-
-  /* Get the next block before marking the new end */
-  extraBlock = 
-    StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
-
-  /* Mark the new end of chain */
-  StorageImpl_SetNextBlockInChain(
-    This->parentStorage, 
-    blockIndex, 
-    BLOCK_END_OF_CHAIN);
-
-  This->tailIndex = blockIndex;
-  This->numBlocks = numBlocks;
-
-  /*
-   * Mark the extra blocks as free
-   */
-  while (extraBlock != BLOCK_END_OF_CHAIN)
-  {
-    blockIndex = 
-      StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
-
-    StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
-    extraBlock = blockIndex;
-  }
-
-  return TRUE;
-}
-
-/******************************************************************************
- *      BlockChainStream_Enlarge
- *
- * Grows this chain in the big block depot.
- */
-BOOL BlockChainStream_Enlarge(BlockChainStream* This,
-                                ULARGE_INTEGER    newSize)
-{
-  ULONG blockIndex, currentBlock;
-  ULONG newNumBlocks;
-  ULONG oldNumBlocks = 0;
-
-  blockIndex = BlockChainStream_GetHeadOfChain(This);
-
-  /*
-   * Empty chain. Create the head.
-   */
-  if (blockIndex == BLOCK_END_OF_CHAIN)
-  {
-    blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
-    StorageImpl_SetNextBlockInChain(This->parentStorage,
-                                      blockIndex,
-                                      BLOCK_END_OF_CHAIN);
-
-    if (This->headOfStreamPlaceHolder != 0)
-    {
-      *(This->headOfStreamPlaceHolder) = blockIndex;
-    }
-    else
-    {
-      StgProperty chainProp;
-      assert(This->ownerPropertyIndex != PROPERTY_NULL);
-
-      StorageImpl_ReadProperty(
-        This->parentStorage, 
-        This->ownerPropertyIndex,
-        &chainProp);
-
-      chainProp.startingBlock = blockIndex; 
-
-      StorageImpl_WriteProperty(
-        This->parentStorage, 
-        This->ownerPropertyIndex,
-        &chainProp);
-    }
-
-    This->tailIndex = blockIndex;
-    This->numBlocks = 1;
-  }
-
-  /*
-   * Figure out how many blocks are needed to contain this stream
-   */
-  newNumBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
-
-  if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
-    newNumBlocks++;
-
-  /*
-   * Go to the current end of chain
-   */
-  currentBlock = BlockChainStream_TailIndex(This);
-  oldNumBlocks = BlockChainStream_NumBlocks(This);
-
-  /*
-   * Add new blocks to the chain
-   */
-  if (oldNumBlocks < newNumBlocks)
-  {
-    while (oldNumBlocks < newNumBlocks)
-    {
-      blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
-
-      StorageImpl_SetNextBlockInChain(
-	This->parentStorage, 
-	currentBlock, 
-	blockIndex);
-
-      StorageImpl_SetNextBlockInChain(
-        This->parentStorage, 
-	blockIndex, 
-	BLOCK_END_OF_CHAIN);
-
-      currentBlock = blockIndex;
-      oldNumBlocks++;
-    }
-
-    This->tailIndex = blockIndex;
-    This->numBlocks = newNumBlocks;
-  }
-
-  return TRUE;
-}
-
-/******************************************************************************
- *      BlockChainStream_SetSize
- *
- * Sets the size of this stream. The big block depot will be updated.
- * The file will grow if we grow the chain.
- *
- * TODO: Free the actual blocks in the file when we shrink the chain.
- *       Currently, the blocks are still in the file. So the file size
- *       doesn't shrink even if we shrink streams. 
- */
-BOOL BlockChainStream_SetSize(
-  BlockChainStream* This,
-  ULARGE_INTEGER    newSize)
-{
-  ULARGE_INTEGER size = BlockChainStream_GetSize(This);
-
-  if (newSize.LowPart == size.LowPart)
-    return TRUE;
-
-  if (newSize.LowPart < size.LowPart)
-  {
-    BlockChainStream_Shrink(This, newSize);
-  }
-  else
-  {
-    ULARGE_INTEGER fileSize = 
-      BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
-
-    ULONG diff = newSize.LowPart - size.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.LowPart += diff;
-    BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
-
-    BlockChainStream_Enlarge(This, newSize);
-  }
-
-  return TRUE;
-}
-
-/******************************************************************************
- *      BlockChainStream_GetSize
- *
- * Returns the size of this chain.
- * Will return the block count if this chain doesn't have a property.
- */
-ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
-{
-  StgProperty chainProperty;
-
-  if(This->headOfStreamPlaceHolder == NULL)
-  {
-    /* 
-     * This chain is a data stream read the property and return 
-     * the appropriate size
-     */
-    StorageImpl_ReadProperty(
-      This->parentStorage,
-      This->ownerPropertyIndex,
-      &chainProperty);
-
-    return chainProperty.size;
-  }
-  else
-  {
-    /*
-     * this chain is a chain that does not have a property, figure out the 
-     * size by making the product number of used blocks times the 
-     * size of them
-     */
-    ULARGE_INTEGER result;
-    result.HighPart = 0;
-
-    result.LowPart  = 
-      BlockChainStream_GetCount(This) * 
-      This->parentStorage->bigBlockSize;
-
-    return result;
-  }
-}
-
-/******************************************************************************
-** SmallBlockChainStream implementation
-*/
-
-SmallBlockChainStream* SmallBlockChainStream_Construct(
-  StorageImpl* parentStorage,  
-  ULONG          propertyIndex)
-{
-  SmallBlockChainStream* newStream;
-
-  newStream =
-      (SmallBlockChainStream *)HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
-
-  newStream->parentStorage      = parentStorage;
-  newStream->ownerPropertyIndex = propertyIndex;
-
-  return newStream;
-}
-
-void SmallBlockChainStream_Destroy(
-  SmallBlockChainStream* This)
-{
-  HeapFree(GetProcessHeap(), 0, This);
-}
-
-/******************************************************************************
- *      SmallBlockChainStream_GetHeadOfChain
- *
- * Returns the head of this chain of small blocks.
- */
-ULONG SmallBlockChainStream_GetHeadOfChain(
-  SmallBlockChainStream* This)
-{
-  StgProperty chainProperty;
-  BOOL      readSucessful;
-
-  if (This->ownerPropertyIndex)
-  {
-    readSucessful = StorageImpl_ReadProperty(
-                      This->parentStorage,
-                      This->ownerPropertyIndex,
-                      &chainProperty);
-
-    if (readSucessful)
-    {
-      return chainProperty.startingBlock;
-    }
-
-  }
-
-  return BLOCK_END_OF_CHAIN;
-}
-
-/******************************************************************************
- *      SmallBlockChainStream_GetNextBlockInChain
- *
- * Returns the index of the next small block in this chain.
- * 
- * Return Values:
- *    - BLOCK_END_OF_CHAIN: end of this chain
- *    - BLOCK_UNUSED: small block 'blockIndex' is free
- */
-ULONG SmallBlockChainStream_GetNextBlockInChain(
-  SmallBlockChainStream* This,
-  ULONG                  blockIndex)
-{
-  ULARGE_INTEGER offsetOfBlockInDepot;
-  DWORD  buffer;
-  ULONG  nextBlockInChain = BLOCK_END_OF_CHAIN;
-  ULONG  bytesRead;
-  BOOL success;
-
-  offsetOfBlockInDepot.HighPart = 0;
-  offsetOfBlockInDepot.LowPart  = blockIndex * sizeof(ULONG);
-
-  /*
-   * Read those bytes in the buffer from the small block file.
-   */
-  success = BlockChainStream_ReadAt(
-              This->parentStorage->smallBlockDepotChain,
-              offsetOfBlockInDepot,
-              sizeof(DWORD),
-              &buffer,
-              &bytesRead);
-
-  if (success)
-  {
-    StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
-  }
-
-  return nextBlockInChain;
-}
-
-/******************************************************************************
- *       SmallBlockChainStream_SetNextBlockInChain
- *
- * Writes the index of the next block of the specified block in the small
- * block depot.
- * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
- * To flag a block as free use BLOCK_UNUSED as nextBlock.
- */
-void SmallBlockChainStream_SetNextBlockInChain(
-  SmallBlockChainStream* This,
-  ULONG                  blockIndex,
-  ULONG                  nextBlock)
-{
-  ULARGE_INTEGER offsetOfBlockInDepot;
-  DWORD  buffer;
-  ULONG  bytesWritten;
-
-  offsetOfBlockInDepot.HighPart = 0;
-  offsetOfBlockInDepot.LowPart  = blockIndex * sizeof(ULONG);
-
-  StorageUtl_WriteDWord(&buffer, 0, nextBlock);
-
-  /*
-   * Read those bytes in the buffer from the small block file.
-   */
-  BlockChainStream_WriteAt(
-    This->parentStorage->smallBlockDepotChain,
-    offsetOfBlockInDepot,
-    sizeof(DWORD),
-    &buffer,
-    &bytesWritten);
-}
-
-/******************************************************************************
- *      SmallBlockChainStream_FreeBlock
- *
- * Flag small block 'blockIndex' as free in the small block depot.
- */
-void SmallBlockChainStream_FreeBlock(
-  SmallBlockChainStream* This,
-  ULONG                  blockIndex)
-{
-  SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
-}
-
-/******************************************************************************
- *      SmallBlockChainStream_GetNextFreeBlock
- *
- * Returns the index of a free small block. The small block depot will be
- * enlarged if necessary. The small block chain will also be enlarged if
- * necessary.
- */
-ULONG SmallBlockChainStream_GetNextFreeBlock(
-  SmallBlockChainStream* This)
-{
-  ULARGE_INTEGER offsetOfBlockInDepot;
-  DWORD buffer;
-  ULONG bytesRead;
-  ULONG blockIndex = 0;
-  ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
-  BOOL success = TRUE;
-  ULONG smallBlocksPerBigBlock;
-
-  offsetOfBlockInDepot.HighPart = 0;
-
-  /*
-   * Scan the small block depot for a free block
-   */
-  while (nextBlockIndex != BLOCK_UNUSED)
-  {
-    offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
-
-    success = BlockChainStream_ReadAt(
-                This->parentStorage->smallBlockDepotChain,
-                offsetOfBlockInDepot,
-                sizeof(DWORD),
-                &buffer,
-                &bytesRead);
-
-    /*
-     * If we run out of space for the small block depot, enlarge it
-     */
-    if (success)
-    {
-      StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
-
-      if (nextBlockIndex != BLOCK_UNUSED)
-        blockIndex++;
-    }
-    else
-    {
-      ULONG count = 
-        BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
-
-      ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
-      ULONG nextBlock, newsbdIndex;
-      BYTE* smallBlockDepot;
-
-      nextBlock = sbdIndex;
-      while (nextBlock != BLOCK_END_OF_CHAIN)
-      {
-        sbdIndex = nextBlock;
-        nextBlock = 
-          StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
-      }
-
-      newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
-      if (sbdIndex != BLOCK_END_OF_CHAIN)
-        StorageImpl_SetNextBlockInChain(
-          This->parentStorage, 
-          sbdIndex, 
-          newsbdIndex);
-
-      StorageImpl_SetNextBlockInChain(
-        This->parentStorage, 
-        newsbdIndex, 
-        BLOCK_END_OF_CHAIN);
-
-      /*
-       * Initialize all the small blocks to free
-       */
-      smallBlockDepot = 
-        (BYTE *)StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
-
-      memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
-      StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
-
-      if (count == 0)
-      {
-        /*
-         * We have just created the small block depot.
-         */
-        StgProperty rootProp;
-        ULONG sbStartIndex; 
-
-        /*
-         * Save it in the header
-         */
-        This->parentStorage->smallBlockDepotStart = newsbdIndex;
-        StorageImpl_SaveFileHeader(This->parentStorage);
-
-        /*
-         * And allocate the first big block that will contain small blocks 
-         */
-        sbStartIndex = 
-          StorageImpl_GetNextFreeBigBlock(This->parentStorage);
-
-        StorageImpl_SetNextBlockInChain(
-          This->parentStorage, 
-          sbStartIndex, 
-          BLOCK_END_OF_CHAIN);
-
-        StorageImpl_ReadProperty(
-          This->parentStorage, 
-          This->parentStorage->rootPropertySetIndex, 
-          &rootProp);
-
-        rootProp.startingBlock = sbStartIndex;
-        rootProp.size.HighPart = 0;
-        rootProp.size.LowPart  = This->parentStorage->bigBlockSize;
-
-        StorageImpl_WriteProperty(
-          This->parentStorage, 
-          This->parentStorage->rootPropertySetIndex, 
-          &rootProp);
-      }
-    }
-  }
-
-  smallBlocksPerBigBlock = 
-    This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
-
-  /*
-   * Verify if we have to allocate big blocks to contain small blocks
-   */
-  if (blockIndex % smallBlocksPerBigBlock == 0)
-  {
-    StgProperty rootProp;
-    ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
-
-    StorageImpl_ReadProperty(
-      This->parentStorage, 
-      This->parentStorage->rootPropertySetIndex, 
-      &rootProp);
-
-    if (rootProp.size.LowPart < 
-       (blocksRequired * This->parentStorage->bigBlockSize))
-    {
-      rootProp.size.LowPart += This->parentStorage->bigBlockSize;
-
-      BlockChainStream_SetSize(
-        This->parentStorage->smallBlockRootChain, 
-        rootProp.size);
-
-      StorageImpl_WriteProperty(
-        This->parentStorage, 
-        This->parentStorage->rootPropertySetIndex, 
-        &rootProp);
-    }
-  }
-
-  return blockIndex;
-}
-
-/******************************************************************************
- *      SmallBlockChainStream_ReadAt
- *
- * Reads a specified number of bytes from this chain at the specified offset.
- * bytesRead may be NULL.
- * Failure will be returned if the specified number of bytes has not been read. 
- */
-BOOL SmallBlockChainStream_ReadAt(
-  SmallBlockChainStream* This,
-  ULARGE_INTEGER         offset,
-  ULONG                  size,
-  void*                  buffer,
-  ULONG*                 bytesRead)
-{
-  ULARGE_INTEGER offsetInBigBlockFile;
-  ULONG blockNoInSequence = 
-    offset.LowPart / This->parentStorage->smallBlockSize;
-
-  ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
-  ULONG bytesToReadInBuffer;
-  ULONG blockIndex;
-  ULONG bytesReadFromBigBlockFile;
-  BYTE* bufferWalker;
-
-  /*
-   * This should never happen on a small block file.
-   */
-  assert(offset.HighPart==0);
-
-  /*
-   * Find the first block in the stream that contains part of the buffer.
-   */
-  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
-
-  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
-  {
-    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
-
-    blockNoInSequence--;
-  }
-
-  /*
-   * Start reading the buffer.
-   */
-  *bytesRead   = 0;
-  bufferWalker = (BYTE *)buffer;
-
-  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
-  {
-    /*
-     * Calculate how many bytes we can copy from this small block.
-     */
-    bytesToReadInBuffer = 
-      MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
-
-    /*
-     * Calculate the offset of the small block in the small block file.
-     */
-    offsetInBigBlockFile.HighPart  = 0;
-    offsetInBigBlockFile.LowPart   = 
-      blockIndex * This->parentStorage->smallBlockSize;
-
-    offsetInBigBlockFile.LowPart  += offsetInBlock;
-
-    /*
-     * Read those bytes in the buffer from the small block file.
-     */
-    BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
-      offsetInBigBlockFile,
-      bytesToReadInBuffer,
-      bufferWalker,
-      &bytesReadFromBigBlockFile);
-
-    assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
-
-    /*
-     * Step to the next big block.
-     */
-    blockIndex    = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
-    bufferWalker += bytesToReadInBuffer;
-    size         -= bytesToReadInBuffer;
-    *bytesRead   += bytesToReadInBuffer;
-    offsetInBlock = 0;  /* There is no offset on the next block */
-  }
-
-  return (size == 0);
-}
-
-/******************************************************************************
- *       SmallBlockChainStream_WriteAt
- *
- * Writes the specified number of bytes to this chain at the specified offset.
- * bytesWritten may be NULL.
- * Will fail if not all specified number of bytes have been written.
- */
-BOOL SmallBlockChainStream_WriteAt(
-  SmallBlockChainStream* This,
-  ULARGE_INTEGER offset,
-  ULONG          size,
-  const void*    buffer,
-  ULONG*         bytesWritten)
-{
-  ULARGE_INTEGER offsetInBigBlockFile;
-  ULONG blockNoInSequence = 
-    offset.LowPart / This->parentStorage->smallBlockSize;
-
-  ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
-  ULONG bytesToWriteInBuffer;
-  ULONG blockIndex;
-  ULONG bytesWrittenFromBigBlockFile;
-  BYTE* bufferWalker;
-  
-  /*
-   * This should never happen on a small block file.
-   */
-  assert(offset.HighPart==0);
-  
-  /*
-   * Find the first block in the stream that contains part of the buffer.
-   */
-  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
-  
-  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
-  {
-    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
-    
-    blockNoInSequence--;
-  }
-  
-  /*
-   * Start writing the buffer.
-   *
-   * Here, I'm casting away the constness on the buffer variable
-   * This is OK since we don't intend to modify that buffer.
-   */
-  *bytesWritten   = 0;
-  bufferWalker = (BYTE*)buffer;
-  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
-  {
-    /*
-     * Calculate how many bytes we can copy to this small block.
-     */
-    bytesToWriteInBuffer = 
-      MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
-    
-    /*
-     * Calculate the offset of the small block in the small block file.
-     */
-    offsetInBigBlockFile.HighPart  = 0;
-    offsetInBigBlockFile.LowPart   = 
-      blockIndex * This->parentStorage->smallBlockSize;
-
-    offsetInBigBlockFile.LowPart  += offsetInBlock;
-    
-    /*
-     * Write those bytes in the buffer to the small block file.
-     */
-    BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
-      offsetInBigBlockFile,
-      bytesToWriteInBuffer,
-      bufferWalker,
-      &bytesWrittenFromBigBlockFile);
-    
-    assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
-    
-    /*
-     * Step to the next big block.
-     */
-    blockIndex    = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
-    bufferWalker  += bytesToWriteInBuffer;
-    size          -= bytesToWriteInBuffer;
-    *bytesWritten += bytesToWriteInBuffer;
-    offsetInBlock  = 0;     /* There is no offset on the next block */
-  }
-  
-  return (size == 0);
-}
-
-/******************************************************************************
- *       SmallBlockChainStream_Shrink
- *
- * Shrinks this chain in the small block depot. 
- */
-BOOL SmallBlockChainStream_Shrink(
-  SmallBlockChainStream* This,
-  ULARGE_INTEGER newSize)
-{
-  ULONG blockIndex, extraBlock;
-  ULONG numBlocks;
-  ULONG count = 0;
-
-  numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
-
-  if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
-    numBlocks++;
-
-  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
-
-  /*
-   * Go to the new end of chain
-   */
-  while (count < numBlocks)
-  {
-    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
-    count++;
-  }
-
-  /*
-   * If the count is 0, we have a special case, the head of the chain was
-   * just freed. 
-   */
-  if (count == 0)
-  {
-    StgProperty chainProp;
-
-    StorageImpl_ReadProperty(This->parentStorage, 
-			     This->ownerPropertyIndex,
-			     &chainProp);
-
-    chainProp.startingBlock = BLOCK_END_OF_CHAIN;
-
-    StorageImpl_WriteProperty(This->parentStorage,
-			      This->ownerPropertyIndex,
-			      &chainProp);
-
-    /*
-     * We start freeing the chain at the head block.
-     */
-    extraBlock = blockIndex;
-  }
-  else
-  {
-    /* Get the next block before marking the new end */
-    extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
-
-    /* Mark the new end of chain */
-    SmallBlockChainStream_SetNextBlockInChain(
-      This, 
-      blockIndex, 
-      BLOCK_END_OF_CHAIN);
-  }
-
-  /*
-   * Mark the extra blocks as free
-   */
-  while (extraBlock != BLOCK_END_OF_CHAIN)
-  {
-    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
-    SmallBlockChainStream_FreeBlock(This, extraBlock);
-    extraBlock = blockIndex;
-  }
-
-  return TRUE;  
-}
-
-/******************************************************************************
- *      SmallBlockChainStream_Enlarge
- *
- * Grows this chain in the small block depot.
- */
-BOOL SmallBlockChainStream_Enlarge(
-  SmallBlockChainStream* This,
-  ULARGE_INTEGER newSize)
-{
-  ULONG blockIndex, currentBlock;
-  ULONG newNumBlocks;
-  ULONG oldNumBlocks = 0;
-
-  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
-
-  /*
-   * Empty chain
-   */
-  if (blockIndex == BLOCK_END_OF_CHAIN)
-  {
-
-    StgProperty chainProp;
-
-    StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
-                               &chainProp);
-
-    chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
-
-    StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
-                                &chainProp);
-
-    blockIndex = chainProp.startingBlock;
-    SmallBlockChainStream_SetNextBlockInChain(
-      This, 
-      blockIndex, 
-      BLOCK_END_OF_CHAIN);
-  }
-
-  currentBlock = blockIndex;
-
-  /*
-   * Figure out how many blocks are needed to contain this stream
-   */
-  newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
-
-  if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
-    newNumBlocks++;
-
-  /*
-   * Go to the current end of chain
-   */
-  while (blockIndex != BLOCK_END_OF_CHAIN)
-  {
-    oldNumBlocks++;
-    currentBlock = blockIndex;
-    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
-  }
-
-  /*
-   * Add new blocks to the chain
-   */
-  while (oldNumBlocks < newNumBlocks)
-  {
-    blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
-    SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
-
-    SmallBlockChainStream_SetNextBlockInChain(
-      This, 
-      blockIndex, 
-      BLOCK_END_OF_CHAIN);
-
-    currentBlock = blockIndex;
-    oldNumBlocks++;
-  }
-
-  return TRUE;
-}
-
-/******************************************************************************
- *      SmallBlockChainStream_GetCount
- *
- * Returns the number of blocks that comprises this chain.
- * This is not the size of this chain as the last block may not be full!
- */
-ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
-{
-  ULONG blockIndex;
-  ULONG count = 0;
-
-  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
-
-  while (blockIndex != BLOCK_END_OF_CHAIN)
-  {
-    count++;
-
-    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
-  }
-
-  return count;
-}
-
-/******************************************************************************
- *      SmallBlockChainStream_SetSize
- *
- * Sets the size of this stream.
- * The file will grow if we grow the chain.
- *
- * TODO: Free the actual blocks in the file when we shrink the chain.
- *       Currently, the blocks are still in the file. So the file size
- *       doesn't shrink even if we shrink streams. 
- */
-BOOL SmallBlockChainStream_SetSize(
-                SmallBlockChainStream* This,
-                ULARGE_INTEGER    newSize)
-{
-  ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
-
-  if (newSize.LowPart == size.LowPart)
-    return TRUE;
-
-  if (newSize.LowPart < size.LowPart)
-  {
-    SmallBlockChainStream_Shrink(This, newSize);
-  }
-  else
-  {
-    SmallBlockChainStream_Enlarge(This, newSize);
-  }
-
-  return TRUE;
-}
-
-/******************************************************************************
- *      SmallBlockChainStream_GetSize
- *
- * Returns the size of this chain.
- */
-ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
-{
-  StgProperty chainProperty;
-
-  StorageImpl_ReadProperty(
-    This->parentStorage,
-    This->ownerPropertyIndex,
-    &chainProperty);
-
-  return chainProperty.size;
-}
-
-/******************************************************************************
- *    StgCreateDocfile32  [OLE32.144]
- */
-HRESULT WINAPI StgCreateDocfile(
-  LPCOLESTR pwcsName,
-  DWORD       grfMode,
-  DWORD       reserved,
-  IStorage  **ppstgOpen)
-{
-  StorageImpl* newStorage = 0;
-  HANDLE       hFile      = INVALID_HANDLE_VALUE;
-  HRESULT        hr         = S_OK;
-  DWORD          shareMode;
-  DWORD          accessMode;
-  DWORD          creationMode;
-  DWORD          fileAttributes;
-  WCHAR          tempFileName[MAX_PATH];
-  BOOL           switchRemoteToLocalFile = TRUE;
-
-  TRACE("(%s, %lx, %ld, %p)\n", 
-	debugstr_w(pwcsName), grfMode, 
-	reserved, ppstgOpen);
-
-  /*
-   * Validate the parameters
-   */
-  if (ppstgOpen == 0)
-    return STG_E_INVALIDPOINTER;
-
-  /*
-   * Validate the STGM flags
-   */
-  if ( FAILED( validateSTGM(grfMode) ))
-    return STG_E_INVALIDFLAG;
-
-  /*
-   * Generate a unique name.
-   */
-  if (pwcsName == 0)
-  {
-    WCHAR tempPath[MAX_PATH];
-    WCHAR prefix[] = { 'S', 'T', 'O', 0 };
-
-    switchRemoteToLocalFile = FALSE;
-
-    memset(tempPath, 0, sizeof(tempPath));
-    memset(tempFileName, 0, sizeof(tempFileName));
-
-    if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
-      tempPath[0] = '.';
-
-    if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
-      pwcsName = tempFileName;
-    else
-      return STG_E_INSUFFICIENTMEMORY;
-  }
-
-  /*
-   * Interpret the STGM value grfMode 
-   */
-  shareMode    = GetShareModeFromSTGM(grfMode);
-  accessMode   = GetAccessModeFromSTGM(grfMode);
-  creationMode = GetCreationModeFromSTGM(grfMode);
-
-  if (grfMode & STGM_DELETEONRELEASE)
-    fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
-  else
-    fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
-
-  if (grfMode & STGM_TRANSACTED)
-    FIXME("Transacted mode not implemented.\n");
-
-  /*
-   * Initialize the "out" parameter.
-   */
-  *ppstgOpen = 0;
-
-  hFile = CreateFileW(pwcsName,
-                        accessMode,
-                        shareMode,
-            NULL,
-                        creationMode,
-                        fileAttributes,
-            0);
- 
-  if (hFile == INVALID_HANDLE_VALUE)
-  {
-    return E_FAIL;
-  }
-
-  /*
-   * Allocate and initialize the new IStorage32object.
-   */
-  newStorage = (StorageImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
- 
-  if (newStorage == 0)
-    return STG_E_INSUFFICIENTMEMORY;
-
-  hr = StorageImpl_Construct(
-         newStorage,
-         hFile,
-         NULL,
-         grfMode,
-         TRUE,
-         TRUE);
- 
-  if (FAILED(hr))
-  {
-    HeapFree(GetProcessHeap(), 0, newStorage);
-    return hr;
-  }
-
-  /*
-   * Get an "out" pointer for the caller.
-   */
-  hr = StorageBaseImpl_QueryInterface(
-         (IStorage*)newStorage,
-         (REFIID)&IID_IStorage,
-         (void**)ppstgOpen);
-
-  return hr;
-}
-
-/******************************************************************************
- *              StgOpenStorage32        [OLE32.148]
- */
-HRESULT WINAPI StgOpenStorage(
-  const OLECHAR *pwcsName,
-  IStorage      *pstgPriority,
-  DWORD           grfMode,
-  SNB           snbExclude,
-  DWORD           reserved, 
-  IStorage      **ppstgOpen)
-{
-  StorageImpl* newStorage = 0;
-  HRESULT        hr = S_OK;
-  HANDLE       hFile = 0;
-  DWORD          shareMode;
-  DWORD          accessMode;
-
-  TRACE("(%s, %p, %lx, %p, %ld, %p)\n", 
-	debugstr_w(pwcsName), pstgPriority, grfMode,
-	snbExclude, reserved, ppstgOpen);
-
-  /*
-   * Perform a sanity check
-   */
-  if (( pwcsName == 0) || (ppstgOpen == 0) )
-    return STG_E_INVALIDPOINTER;
-
-  /*
-   * Validate the STGM flags
-   */
-  if ( FAILED( validateSTGM(grfMode) ))
-    return STG_E_INVALIDFLAG;
-
-  /*
-   * Interpret the STGM value grfMode
-   */
-  shareMode    = GetShareModeFromSTGM(grfMode);
-  accessMode   = GetAccessModeFromSTGM(grfMode);
-
-  /*
-   * Initialize the "out" parameter.
-   */
-  *ppstgOpen = 0;
-  
-  hFile = CreateFileW( pwcsName, 
-                       accessMode,
-                       shareMode,
-                       NULL,
-                       OPEN_EXISTING,
-                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
-                       0);
-  
-  
-  if (hFile==INVALID_HANDLE_VALUE)
-  {
-    HRESULT hr = E_FAIL;
-    DWORD last_error = GetLastError();
-
-    switch (last_error)
-    {
-      case ERROR_FILE_NOT_FOUND:
-        hr = STG_E_FILENOTFOUND;
-        break;
-
-      case ERROR_PATH_NOT_FOUND:
-        hr = STG_E_PATHNOTFOUND;
-        break;
-
-      case ERROR_ACCESS_DENIED:
-      case ERROR_WRITE_PROTECT:
-        hr = STG_E_ACCESSDENIED;
-        break;
-
-      case ERROR_SHARING_VIOLATION:
-        hr = STG_E_SHAREVIOLATION;
-        break;
-
-      default:
-        hr = E_FAIL;
-    }
-
-    return hr;
-  }
-
-  /*
-   * Allocate and initialize the new IStorage32object.
-   */
-  newStorage = (StorageImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
-  
-  if (newStorage == 0)
-    return STG_E_INSUFFICIENTMEMORY;
-
-  hr = StorageImpl_Construct(
-         newStorage,
-         hFile,
-         NULL,
-         grfMode,
-         TRUE,
-         FALSE);
-  
-  if (FAILED(hr))
-  {
-    HeapFree(GetProcessHeap(), 0, newStorage);
-    return hr;
-  }
-  
-  /*
-   * Get an "out" pointer for the caller.
-   */
-  hr = StorageBaseImpl_QueryInterface(
-         (IStorage*)newStorage,
-         (REFIID)&IID_IStorage,
-         (void**)ppstgOpen);
-  
-  return hr;
-}
-
-/******************************************************************************
- *    StgCreateDocfileOnILockBytes    [OLE32.145]
- */
-HRESULT WINAPI StgCreateDocfileOnILockBytes(
-      ILockBytes *plkbyt,
-      DWORD grfMode,
-      DWORD reserved,
-      IStorage** ppstgOpen)
-{
-  StorageImpl*   newStorage = 0;
-  HRESULT        hr         = S_OK;
-
-  /*
-   * Validate the parameters
-   */
-  if ((ppstgOpen == 0) || (plkbyt == 0))
-    return STG_E_INVALIDPOINTER;
-
-  /*
-   * Allocate and initialize the new IStorage object.
-   */
-  newStorage = (StorageImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
-
-  if (newStorage == 0)
-    return STG_E_INSUFFICIENTMEMORY;
-
-  hr = StorageImpl_Construct(
-         newStorage,
-         0,
-         plkbyt,
-         grfMode,
-         FALSE,
-         TRUE);
-
-  if (FAILED(hr))
-  {
-    HeapFree(GetProcessHeap(), 0, newStorage);
-    return hr;
-  }
-
-  /*
-   * Get an "out" pointer for the caller.
-   */
-  hr = StorageBaseImpl_QueryInterface(
-         (IStorage*)newStorage,
-         (REFIID)&IID_IStorage,
-         (void**)ppstgOpen);
-
-  return hr;  
-}
-
-/******************************************************************************
- *    StgOpenStorageOnILockBytes    [OLE32.149]
- */
-HRESULT WINAPI StgOpenStorageOnILockBytes(
-      ILockBytes *plkbyt,
-      IStorage *pstgPriority,
-      DWORD grfMode,
-      SNB snbExclude,
-      DWORD reserved,
-      IStorage **ppstgOpen)
-{
-  StorageImpl* newStorage = 0;
-  HRESULT        hr = S_OK;
-
-  /*
-   * Perform a sanity check
-   */
-  if ((plkbyt == 0) || (ppstgOpen == 0))
-    return STG_E_INVALIDPOINTER;
-
-  /*
-   * Validate the STGM flags
-   */
-  if ( FAILED( validateSTGM(grfMode) ))
-    return STG_E_INVALIDFLAG;
-
-  /*
-   * Initialize the "out" parameter.
-   */
-  *ppstgOpen = 0;
-
-  /*
-   * Allocate and initialize the new IStorage object.
-   */
-  newStorage = (StorageImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
- 
-  if (newStorage == 0)
-    return STG_E_INSUFFICIENTMEMORY;
-
-  hr = StorageImpl_Construct(
-         newStorage,
-         0,
-         plkbyt,
-         grfMode,
-         FALSE,
-         FALSE);
-
-  if (FAILED(hr))
-  {
-    HeapFree(GetProcessHeap(), 0, newStorage);
-    return hr;
-  }
-
-  /*
-   * Get an "out" pointer for the caller.
-   */
-  hr = StorageBaseImpl_QueryInterface(
-         (IStorage*)newStorage,
-         (REFIID)&IID_IStorage,
-         (void**)ppstgOpen);
-
-  return hr;
-}
-
-/******************************************************************************
- *              StgIsStorageILockBytes        [OLE32.147]
- *
- * Determines if the ILockBytes contains a storage object.
- */
-HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
-{
-  BYTE sig[8];
-  ULARGE_INTEGER offset;
-
-  offset.HighPart = 0;
-  offset.LowPart  = 0;
-
-  ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
-
-  if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
-    return S_OK;
-
-  return S_FALSE;
-}
-
-/******************************************************************************
- *              WriteClassStg32        [OLE32.158]
- *
- * This method will store the specified CLSID in the specified storage object
- */
-HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
-{
-  HRESULT hRes;
-
-  assert(pStg != 0);
-
-  hRes = IStorage_SetClass(pStg, rclsid);
-
-  return hRes;
-}
-
-/*******************************************************************************************
- *    ReadClassStg
- *
- * This method reads the CLSID previously written to a storage object with the WriteClassStg.
- */
-HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
-
-    STATSTG pstatstg;
-    HRESULT hRes;
-    
-    TRACE("()\n");
-
-    if(pclsid==NULL)
-        return E_POINTER;
-   /*
-    * read a STATSTG structure (contains the clsid) from the storage
-    */
-    hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
-
-    if(SUCCEEDED(hRes))
-        *pclsid=pstatstg.clsid;
-
-    return hRes;
-}
-
-/*************************************************************************************
- *    OleLoadFromStream
- *
- * This function loads an object from stream
- */
-HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
-{
-    CLSID clsid;
-    HRESULT res;
-
-/* For this function to work.  All registry keys related to Interface must be in            */
-/* Installed in the wine registry (eg. Search for IFileMoniker in the windows registry,     */
-/* copy the missing CLSID keys (and all contents) to wine registry). Implement              */
-/* the OLE32_DllGetClassObject (a big switch for all interface in OLE32.dll to allocate the */
-/* actual interface )                                                                       */
-    FIXME("(),stub!\n");
-
-    res=ReadClassStm(pStm,&clsid);
-
-    if (SUCCEEDED(res)){
-        /* For this to work properly iidInterface should be IUnknown, need to Query */
-        /* for IPersitStream, if successful, query for iidInterface */
-
-        res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
-
-        if (SUCCEEDED(res))
-
-            res=IPersistStream_Load((IPersistStream*)ppvObj,pStm);
-    }
-
-    return res;
-}
-
-/************************************************************************************************
- *    OleSaveToStream
- *
- * This function saves an object with the IPersistStream interface on it to the specified stream
- */
-HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
-{
-
-    CLSID clsid;
-    HRESULT res;
-    
-    TRACE("(%p,%p)\n",pPStm,pStm);
-
-    res=IPersistStream_GetClassID(pPStm,&clsid);
-
-    if (SUCCEEDED(res)){
-        
-        res=WriteClassStm(pStm,&clsid);
-
-        if (SUCCEEDED(res))
-
-            res=IPersistStream_Save(pPStm,pStm,TRUE);
-    }
-
-    TRACE("Finished Save\n");
-    return res;
-}
-
-/****************************************************************************
- * This method validate a STGM parameter that can contain the values below
- *
- * STGM_DIRECT               0x00000000
- * STGM_TRANSACTED           0x00010000
- * STGM_SIMPLE               0x08000000
- * 
- * STGM_READ                 0x00000000
- * STGM_WRITE                0x00000001
- * STGM_READWRITE            0x00000002
- * 
- * STGM_SHARE_DENY_NONE      0x00000040
- * STGM_SHARE_DENY_READ      0x00000030
- * STGM_SHARE_DENY_WRITE     0x00000020
- * STGM_SHARE_EXCLUSIVE      0x00000010
- * 
- * STGM_PRIORITY             0x00040000
- * STGM_DELETEONRELEASE      0x04000000
- *
- * STGM_CREATE               0x00001000
- * STGM_CONVERT              0x00020000
- * STGM_FAILIFTHERE          0x00000000
- *
- * STGM_NOSCRATCH            0x00100000
- * STGM_NOSNAPSHOT           0x00200000
- */
-static HRESULT validateSTGM(DWORD stgm)
-{
-  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);
-
-  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);
-
-  BOOL bSTGM_CREATE           = ((stgm & STGM_CREATE) == STGM_CREATE);
-  BOOL bSTGM_CONVERT          = ((stgm & STGM_CONVERT) == STGM_CONVERT);
-   
-  BOOL bSTGM_NOSCRATCH        = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
-  BOOL bSTGM_NOSNAPSHOT       = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
-
-  /* 
-   * 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) 
-      return E_FAIL;
-
-  /*
-   * STGM_CREATE | STGM_CONVERT
-   * if both are false, STGM_FAILIFTHERE is set to TRUE
-   */
-  if ( bSTGM_CREATE && bSTGM_CONVERT )
-    return E_FAIL;
-
-  /*
-   * STGM_NOSCRATCH requires STGM_TRANSACTED
-   */
-  if ( bSTGM_NOSCRATCH && ! bSTGM_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)) )
-    return E_FAIL;
-  }
-
-  return S_OK;
-}
-
-/****************************************************************************
- *      GetShareModeFromSTGM
- *
- * This method will return a share mode flag from a STGM value.
- * The STGM value is assumed valid. 
- */
-static DWORD GetShareModeFromSTGM(DWORD stgm)
-{
-  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;
-}
-
-/****************************************************************************
- *      GetAccessModeFromSTGM
- *
- * This method will return an access mode flag from a STGM value.
- * The STGM value is assumed valid.
- */
-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;
-}
-
-/****************************************************************************
- *      GetCreationModeFromSTGM
- *
- * This method will return a creation mode flag from a STGM value.
- * The STGM value is assumed valid.
- */
-static DWORD GetCreationModeFromSTGM(DWORD stgm)
-{
-  if ( stgm & STGM_CREATE)
-    return CREATE_ALWAYS;
-  if (stgm & STGM_CONVERT) {
-    FIXME("STGM_CONVERT not implemented!\n");
-    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;
-}
-
-BOOL OLECONVERT_IsStorageLink(LPSTORAGE pStorage)
-{
-    STATSTG stat;
-
-    IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
-    
-    return IsEqualCLSID(&IID_StdOleLink, &stat.clsid);
-}
-
-/*************************************************************************
- * OLECONVERT_LoadOLE10 [Internal] 
- *
- * Loads the OLE10 STREAM to memory 
- *
- * PARAMS
- *     pOleStream   [I] The OLESTREAM
- *     pData        [I] Data Structure for the OLESTREAM Data
- *
- * RETURNS
- *     Success:  S_OK
- *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
- *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
- *
- * NOTES
- *     This function is used by OleConvertOLESTREAMToIStorage only.
- *     
- *     Memory allocated for pData must be freed by the caller
- */
-HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData)
-{
-    DWORD dwSize;
-    pData->pData = NULL;
-    pData->pLinkExtraInfo = NULL;
-    pData->strLinkFileName = NULL;
-
-    /* Get the OleID */
-    dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)&(pData->dwOleID), sizeof(pData->dwOleID));
-    if(dwSize != sizeof(pData->dwOleID))
-    {
-         return CONVERT10_E_OLESTREAM_GET;
-    }
-    else if(pData->dwOleID != OLESTREAM_ID)
-    {
-        return CONVERT10_E_OLESTREAM_FMT;
-    }
-
-    /* Get the TypeID...more info needed for this field */
-    dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)&(pData->dwObjectTypeID), sizeof(pData->dwObjectTypeID));
-
-    if(dwSize != sizeof(pData->dwObjectTypeID))
-    {
-        return CONVERT10_E_OLESTREAM_GET;
-    }
-    if(pData->dwObjectTypeID != 0)
-    {
-        if(pData->dwObjectTypeID != OLECONVERT_LINK_TYPE 
-            && pData->dwObjectTypeID != OLECONVERT_EMBEDDED_TYPE
-            && pData->dwObjectTypeID != OLECONVERT_PRESENTATION_DATA_TYPE)
-        {
-            FIXME("Unknown ObjectTypeID: %lx\n", pData->dwObjectTypeID);
-        }
-
-        /* Get the lenght of the OleTypeName */
-        dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
-        if(dwSize != sizeof(pData->dwOleTypeNameLength))
-        {
-            return CONVERT10_E_OLESTREAM_GET;
-        }
-        if(pData->dwOleTypeNameLength > 0)
-        {
-            /* Get the OleTypeName */
-            dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)pData->strOleTypeName, pData->dwOleTypeNameLength);
-            if(dwSize != pData->dwOleTypeNameLength)
-            {
-                return CONVERT10_E_OLESTREAM_GET;
-            }
-        }
-        if(pData->dwObjectTypeID == OLECONVERT_LINK_TYPE)
-        {
-            dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR) &(pData->dwLinkFileNameLength), sizeof(pData->dwLinkFileNameLength));
-            if(dwSize != sizeof(pData->dwLinkFileNameLength))
-            {
-                return CONVERT10_E_OLESTREAM_GET;
-            }
-
-            if(pData->dwLinkFileNameLength > 0)
-            {
-                pData->strLinkFileName = (BYTE *)malloc(pData->dwLinkFileNameLength);
-                if(pData->strLinkFileName == NULL)
-                {
-                    return E_OUTOFMEMORY;
-                }
-                dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR) pData->strLinkFileName, pData->dwLinkFileNameLength);
-                if(dwSize != pData->dwLinkFileNameLength)
-                {
-                    return CONVERT10_E_OLESTREAM_GET;
-                }
-            }
-            dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR) &(pData->dwLinkExtraInfoLength), sizeof(pData->dwLinkExtraInfoLength));
-            if(dwSize != sizeof(pData->dwLinkExtraInfoLength))
-            {
-                return CONVERT10_E_OLESTREAM_GET;
-            }
-          
-            if(pData->dwLinkExtraInfoLength > 0)
-            {
-                pData->pLinkExtraInfo = (BYTE *)malloc(pData->dwLinkExtraInfoLength);
-                if(pData->pLinkExtraInfo == NULL)
-                {
-                    return E_OUTOFMEMORY;
-                }
-                dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR) pData->pLinkExtraInfo, pData->dwLinkExtraInfoLength);
-                if(dwSize != pData->dwLinkExtraInfoLength)
-                {
-                    return CONVERT10_E_OLESTREAM_GET;
-                }
-            }
-        }
-
-        /* Get the Width of the Metafile */
-        dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
-        if(dwSize != sizeof(pData->dwMetaFileWidth))
-        {
-            return CONVERT10_E_OLESTREAM_GET;
-        }
-
-        /* Get the Height of the Metafile */
-        dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
-        if(dwSize != sizeof(pData->dwMetaFileHeight))
-        {
-            return CONVERT10_E_OLESTREAM_GET;
-        }
-
-        /* Get the Length of the Data */
-        dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)&(pData->dwDataLength), sizeof(pData->dwDataLength));
-        if(dwSize != sizeof(pData->dwDataLength))
-        {
-            return CONVERT10_E_OLESTREAM_GET;
-        }
-        if(pData->dwDataLength > 0)
-        {
-            pData->pData = (BYTE *)malloc(pData->dwDataLength);
-            if(pData->pData == NULL)
-            {
-                return E_OUTOFMEMORY;
-            }
-            /* Get Data (ex. IStorage, Metafile, or BMP) */
-            dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)pData->pData, pData->dwDataLength);
-            if(dwSize != pData->dwDataLength)
-            {
-                return CONVERT10_E_OLESTREAM_GET;
-            }
-        }
-    }
-    return S_OK;
-}
-
-
-/*************************************************************************
- * OLECONVERT_SaveOLE10 [Internal] 
- *
- * Saves the OLE10 STREAM From memory 
- *
- * PARAMS
- *     pData        [I] Data Structure for the OLESTREAM Data
- *     pOleStream   [I] The OLESTREAM to save
- *
- * RETURNS
- *     Success:  S_OK
- *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
- *
- * NOTES
- *     This function is used by OleConvertIStorageToOLESTREAM only.
- *     
- */
-HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
-{
-    DWORD dwSize;
-    HRESULT hRes = S_OK;
-
-
-   /* Set the OleID */
-    dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwOleID), sizeof(pData->dwOleID));
-    if(dwSize != sizeof(pData->dwOleID))
-    {
-        return CONVERT10_E_OLESTREAM_PUT;
-    }
-
-    /* Set the TypeID */
-    dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwObjectTypeID), sizeof(pData->dwObjectTypeID));
-    if(dwSize != sizeof(pData->dwObjectTypeID))
-    {
-        return CONVERT10_E_OLESTREAM_PUT;
-    }
-
-    if(pData->dwOleID == OLESTREAM_ID && pData->dwObjectTypeID != 0 && hRes == S_OK)
-    {
-        /* Set the Length of the OleTypeName */
-        dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
-        if(dwSize != sizeof(pData->dwOleTypeNameLength))
-        {
-            return CONVERT10_E_OLESTREAM_PUT;
-        }
-
-        if(pData->dwOleTypeNameLength > 0)
-        {
-            /* Set the OleTypeName */
-            dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)  pData->strOleTypeName, pData->dwOleTypeNameLength);
-            if(dwSize != pData->dwOleTypeNameLength)
-            {
-                return CONVERT10_E_OLESTREAM_PUT;
-            }
-        }
-
-        if(pData->dwObjectTypeID == OLECONVERT_LINK_TYPE)
-        {
-            dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR) &(pData->dwLinkFileNameLength), sizeof(pData->dwLinkFileNameLength));
-            if(dwSize != sizeof(pData->dwLinkFileNameLength))
-            {
-                return CONVERT10_E_OLESTREAM_GET;
-            }
-
-            if(pData->dwLinkFileNameLength > 0)
-            {
-                dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR) pData->strLinkFileName, pData->dwLinkFileNameLength);
-                if(dwSize != pData->dwLinkFileNameLength)
-                {
-                    return CONVERT10_E_OLESTREAM_GET;
-                }
-            }
-
-            dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR) &(pData->dwLinkExtraInfoLength), sizeof(pData->dwLinkExtraInfoLength));
-            if(dwSize != sizeof(pData->dwLinkExtraInfoLength))
-            {
-                return CONVERT10_E_OLESTREAM_GET;
-            }
-          
-            if(pData->dwLinkExtraInfoLength > 0)
-            {
-                dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR) pData->pLinkExtraInfo, pData->dwLinkExtraInfoLength);
-                if(dwSize != pData->dwLinkExtraInfoLength)
-                {
-                    return CONVERT10_E_OLESTREAM_GET;
-                }
-            }
-        }
-
-        /* Set the width of the Metafile */
-        dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
-        if(dwSize != sizeof(pData->dwMetaFileWidth))
-        {
-            return CONVERT10_E_OLESTREAM_PUT;
-        }
-
-        /* Set the height of the Metafile */
-        dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
-        if(dwSize != sizeof(pData->dwMetaFileHeight))
-        {
-            return CONVERT10_E_OLESTREAM_PUT;
-        }
-
-        /* Set the lenght of the Data */
-        dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwDataLength), sizeof(pData->dwDataLength));
-        if(dwSize != sizeof(pData->dwDataLength))
-        {
-            return CONVERT10_E_OLESTREAM_PUT;
-        }
-
-        if(pData->dwDataLength > 0)
-        {
-            /* Set the Data (eg. IStorage, Metafile, Bitmap) */
-            dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)  pData->pData, pData->dwDataLength);
-            if(dwSize != pData->dwDataLength)
-            {
-                return CONVERT10_E_OLESTREAM_PUT;
-            }
-        }
-    }
-    return S_OK;
-}
-
-/*************************************************************************
- * OLECONVERT_GetOLE20FromOLE10[Internal] 
- *
- * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
- * opens it, and copies the content to the dest IStorage for 
- * OleConvertOLESTREAMToIStorage
- * 
- *
- * PARAMS
- *     pDestStorage  [I] The IStorage to copy the data to
- *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
- *     nBufferLength [I] The size of the buffer
- *
- * RETURNS
- *     Nothing
- *
- * NOTES
- *     
- *     
- */
-void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
-{
-    HRESULT hRes;
-    HANDLE hFile;
-    IStorage *pTempStorage;
-    DWORD dwNumOfBytesWritten;
-    WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
-    WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
-
-    /* Create a temp File */
-    GetTempPathW(MAX_PATH, wstrTempDir);
-    GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
-    hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-
-    if(hFile != INVALID_HANDLE_VALUE)
-    {
-        /* Write IStorage Data to File */
-        WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
-        CloseHandle(hFile);
-
-        /* Open and copy temp storage to the Dest Storage */
-        hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
-        if(hRes == S_OK)
-        {
-            hRes = StorageImpl_CopyTo(pTempStorage, NULL,NULL,NULL, pDestStorage);
-            StorageBaseImpl_Release(pTempStorage);
-        }
-        DeleteFileW(wstrTempFile);
-    }
-}
-
-
-/*************************************************************************
- * OLECONVERT_WriteOLE20ToBuffer [Internal] 
- *
- * Saves the OLE10 STREAM From memory 
- *
- * PARAMS
- *     pStorage  [I] The Src IStorage to copy
- *     pData     [I] The Dest Memory to write to.
- *
- * RETURNS
- *     The size in bytes allocated for pData
- *
- * NOTES
- *     Memory allocated for pData must be freed by the caller
- *
- *     Used by OleConvertIStorageToOLESTREAM only.
- *     
- */
-DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
-{
-    HANDLE hFile;
-    HRESULT hRes;
-    DWORD nDataLength = 0;
-    IStorage *pTempStorage;
-    WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
-    WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
-
-    *pData = NULL;
-    
-    /* Create temp Storage */
-    GetTempPathW(MAX_PATH, wstrTempDir);
-    GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
-    hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, &pTempStorage);
-
-    if(hRes == S_OK)
-    {
-        /* Copy Src Storage to the Temp Storage */
-        StorageImpl_CopyTo(pStorage, NULL,NULL,NULL, pTempStorage);
-        StorageBaseImpl_Release(pTempStorage);
-
-        /* Open Temp Storage as a file and copy to memory */
-        hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-        if(hFile != INVALID_HANDLE_VALUE)
-        {
-            nDataLength = GetFileSize(hFile, NULL);
-            *pData = (BYTE *) malloc(nDataLength);
-            ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
-            CloseHandle(hFile);
-        }
-        DeleteFileW(wstrTempFile);
-    }
-    return nDataLength;
-}
-
-/*************************************************************************
- * OLECONVERT_CreateEmbeddedOleStream [Internal] 
- *
- * Creates the "\001OLE" stream in the IStorage if neccessary.
- *
- * PARAMS
- *     pStorage     [I] Dest storage to create the stream in
- *
- * RETURNS
- *     Nothing
- *
- * NOTES
- *     This function is used by OleConvertOLESTREAMToIStorage only.
- *
- *     This stream is still unknown, MS Word seems to have extra data
- *     but since the data is stored in the OLESTREAM there should be
- *     no need to recreate the stream.  If the stream is manually 
- *     deleted it will create it with this default data.
- *     
- */
-void OLECONVERT_CreateEmbeddedOleStream(LPSTORAGE pStorage)
-{
-    HRESULT hRes;
-    IStream *pStream;
-    WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
-    BYTE pOleStreamHeader [] = 
-    {
-        0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-        0x00, 0x00, 0x00, 0x00 
-    };
-    
-    /* Create stream if not present */
-    hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
-        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
-
-    if(hRes == S_OK)
-    {
-        /* Write default Data */
-        hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
-        IStream_Release(pStream);
-    }
-}
-
-/*************************************************************************
- * OLECONVERT_CreateLinkOleStream [Internal] 
- *
- * Creates the "\001OLE" stream in the IStorage if neccessary.
- *
- * PARAMS
- *     pStorage     [I] Dest storage to create the stream in
- *
- * RETURNS
- *     Nothing
- *
- * NOTES
- *     This function is used by OleConvertOLESTREAMToIStorage only.
- *
- *     This stream is still unknown, MS Word seems to have extra data
- *     but since the data is stored in the OLESTREAM there should be
- *     no need to recreate the stream.  If the stream is manually 
- *     deleted it will create it with this default data.
- *     
- */
-HRESULT OLECONVERT_CreateLinkOleStream(LPSTORAGE pStorage, LPCSTR strProgID, LPCSTR strFileName, BYTE *pItemData, DWORD dwItemDataLength)
-{
-    HRESULT hRes;
-    IStream *pStream;
-    WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
-    OLECONVERT_ISTORAGE_OLE OleStreamHeader;
-    LPMONIKER pFileMoniker=NULL;
-    LPMONIKER pItemMoniker=NULL;
-    LPMONIKER pCompMoniker=NULL;
-    LPMONIKER pDestMoniker=NULL;
-
-
-    BYTE pUnknown7 [] = 
-    {
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-        0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
-    };
-
-    OleStreamHeader.dwOLEHEADER_ID = 0x02000001;
-    OleStreamHeader.dwUnknown1 = 0x01;
-    OleStreamHeader.dwUnknown2 = 0x01;
-    OleStreamHeader.dwUnknown3 = 0x00;
-    OleStreamHeader.dwUnknown4 = 0x00;
-    OleStreamHeader.dwUnknown5 = 0x00;
-    OleStreamHeader.dwUnknown6 = 0xFFFF;
-    hRes = CLSIDFromProgID16(strProgID, &(OleStreamHeader.clsidObject));
-    memcpy(OleStreamHeader.dwUnknown7, pUnknown7, sizeof(pUnknown7));
-
-    if(hRes != S_OK)
-    {
-        return REGDB_E_CLASSNOTREG;
-    }
-
-    if(strFileName != NULL)
-    {
-        WCHAR wstrFileName[MAX_PATH];
-        MultiByteToWideChar(CP_ACP, 0, strFileName, -1, wstrFileName, MAX_PATH); 
-        hRes = CreateFileMoniker(wstrFileName, &pFileMoniker);
-    }
-    if(pItemData != NULL)
-    {
-
-        WCHAR wstrDelim[] = {'!', 0};
-        WCHAR *wstrItem;
-
-        wstrItem = (LPWSTR) malloc(dwItemDataLength * sizeof(WCHAR));
-
-        MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pItemData, -1, wstrItem, dwItemDataLength); 
-        hRes = CreateItemMoniker(wstrDelim, wstrItem, &pItemMoniker);
-
-        free(wstrItem);
-    }
-
-    if(pItemMoniker != NULL && pFileMoniker != NULL)
-    {
-        hRes = CreateGenericComposite(pFileMoniker, pItemMoniker, &pCompMoniker);
-    }
-
-    if(hRes == S_OK)
-    {
-
-        if(pCompMoniker != NULL)
-        {
-            pDestMoniker = pCompMoniker;
-        }
-        else if(pFileMoniker != NULL)
-        {
-            pDestMoniker = pFileMoniker;
-        }
-        else if(pItemMoniker != NULL)
-        {
-            pDestMoniker = pItemMoniker;
-        }
-
-
-        if(pDestMoniker != NULL)
-        {
-            ULARGE_INTEGER liFileMonikerSize;
-            IMoniker_GetClassID(pDestMoniker, &(OleStreamHeader.clsidMonikerTypeID));
-            IMoniker_GetSizeMax(pDestMoniker, &liFileMonikerSize);
-            OleStreamHeader.dwObjectCLSIDOffset = liFileMonikerSize.LowPart + sizeof(OleStreamHeader.dwUnknown6) + sizeof(OleStreamHeader.clsidMonikerTypeID);
-        }
-        
-
-        /* Create stream  (shouldn't be present)*/
-        hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
-            STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
-
-        if(hRes == S_OK)
-        {
-            /* Write default Data */
-            IStream_Write(pStream, &(OleStreamHeader.dwOLEHEADER_ID), sizeof(OleStreamHeader.dwOLEHEADER_ID), NULL);
-            IStream_Write(pStream, &(OleStreamHeader.dwUnknown1), sizeof(OleStreamHeader.dwUnknown1), NULL);
-            IStream_Write(pStream, &(OleStreamHeader.dwUnknown2), sizeof(OleStreamHeader.dwUnknown2), NULL);
-            IStream_Write(pStream, &(OleStreamHeader.dwUnknown3), sizeof(OleStreamHeader.dwUnknown3), NULL);
-            IStream_Write(pStream, &(OleStreamHeader.dwUnknown4), sizeof(OleStreamHeader.dwUnknown4), NULL);
-            IStream_Write(pStream, &(OleStreamHeader.dwUnknown5), sizeof(OleStreamHeader.dwUnknown5), NULL);
-            IStream_Write(pStream, &(OleStreamHeader.dwObjectCLSIDOffset), sizeof(OleStreamHeader.dwObjectCLSIDOffset), NULL);
-            /* Should call OleSaveToStream */
-            WriteClassStm(pStream, &(OleStreamHeader.clsidMonikerTypeID));
-            if(pDestMoniker != NULL)
-            {
-                IMoniker_Save(pDestMoniker, pStream, FALSE);
-            }
-            IStream_Write(pStream, &(OleStreamHeader.dwUnknown6), sizeof(OleStreamHeader.dwUnknown6), NULL);
-            WriteClassStm(pStream, &(OleStreamHeader.clsidObject));
-            IStream_Write(pStream, OleStreamHeader.dwUnknown7, sizeof(OleStreamHeader.dwUnknown7), NULL);
-            IStream_Release(pStream);
-        }
-    }
-    if(pFileMoniker != NULL)
-    {
-        IMoniker_Release(pFileMoniker);
-    }
-    if(pItemMoniker != NULL)
-    {
-        IMoniker_Release(pItemMoniker);
-    }
-    if(pCompMoniker != NULL)
-    {
-        IMoniker_Release(pCompMoniker);
-    }
-    return S_OK;
-}
-
-/*************************************************************************
- * OLECONVERT_CreateCompObjStream [Internal] 
- *
- * Creates a "\001CompObj" is the destination IStorage if necessary.
- *
- * PARAMS
- *     pStorage       [I] The dest IStorage to create the CompObj Stream 
- *                        if necessary.
- *     strOleTypeName [I] The ProgID
- *
- * RETURNS
- *     Success:  S_OK
- *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
- *
- * NOTES
- *     This function is used by OleConvertOLESTREAMToIStorage only.
- *
- *     The stream data is stored in the OLESTREAM and there should be
- *     no need to recreate the stream.  If the stream is manually 
- *     deleted it will attempt to create it by querying the registry.
- *
- *     
- */
-HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
-{
-    IStream *pStream;
-    HRESULT hStorageRes, hRes = S_OK;
-    OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
-    WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
-
-    BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
-    BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
-
-    /* Initialize the CompObj structure */
-    memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
-    memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
-    memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
-
-
-    /*  Create a CompObj stream if it doesn't exist */
-    hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName, 
-        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
-    if(hStorageRes == S_OK)
-    {
-        /* copy the OleTypeName to the compobj struct */
-        IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
-        strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
-
-        /* copy the OleTypeName to the compobj struct */
-        /* Note: in the test made, these where Identical      */
-        IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
-        strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
-
-        /* Get the CLSID */
-        hRes = CLSIDFromProgID16(IStorageCompObj.strProgIDName, &(IStorageCompObj.clsid));
-
-        if(hRes != S_OK)
-        {
-            hRes = REGDB_E_CLASSNOTREG;
-        }
-        else
-        {
-            HKEY hKey;
-            LONG hErr;
-            /* Get the CLSID Default Name from the Registry */
-            hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey); 
-            if(hErr == ERROR_SUCCESS)
-            {
-                char strTemp[OLESTREAM_MAX_STR_LEN];
-                IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
-                hErr = RegQueryValueA(hKey, NULL, strTemp, (LPLONG)&(IStorageCompObj.dwCLSIDNameLength));
-                if(hErr == ERROR_SUCCESS)
-                {
-                    strcpy(IStorageCompObj.strCLSIDName, strTemp);
-                }
-                RegCloseKey(hKey);
-            }
-            if(hErr != ERROR_SUCCESS)
-            {
-                hRes = REGDB_E_CLASSNOTREG;
-            }
-        }
-
-        if(hRes == S_OK )
-        {
-            /* Write CompObj Structure to stream */
-            hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
-            WriteClassStm(pStream,&(IStorageCompObj.clsid));
-            hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
-            if(IStorageCompObj.dwCLSIDNameLength > 0)
-            {
-                hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
-            }
-            hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
-            if(IStorageCompObj.dwOleTypeNameLength > 0)
-            {
-                hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
-            }
-            hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
-            if(IStorageCompObj.dwProgIDNameLength > 0)
-            {
-                hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
-            }
-            hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
-        }
-        IStream_Release(pStream);
-    }
-    return hRes;
-}
-
-
-/*************************************************************************
- * OLECONVERT_CreateOlePresStream[Internal] 
- *
- * Creates the "\002OlePres000" Stream with the Metafile data
- *
- * PARAMS
- *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
- *     dwExtentX    [I] Width of the Metafile
- *     dwExtentY    [I] Height of the Metafile 
- *     pData        [I] Metafile data
- *     dwDataLength [I] Size of the Metafile data
- *
- * RETURNS
- *     Success:  S_OK
- *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
- *
- * NOTES
- *     This function is used by OleConvertOLESTREAMToIStorage only.
- *     
- */
-void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwObjectType, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
-{
-    HRESULT hRes;
-    IStream *pStream;
-    WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
-    BYTE pOlePresStreamEmbeddedHeader [] = 
-    {
-        0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 
-        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
-        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00
-    };
-
-    BYTE pOlePresStreamLinkHeader [] = 
-    {
-        0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 
-        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
-        0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00
-    };
-
-    BYTE pOlePresStreamHeaderEmpty [] = 
-    {
-        0x00, 0x00, 0x00, 0x00, 
-        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
-        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00
-    };
-     
-    /* Create the OlePres000 Stream */
-    hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
-        STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
-
-    if(hRes == S_OK)
-    {
-        DWORD nHeaderSize;
-        OLECONVERT_ISTORAGE_OLEPRES OlePres;
-
-        memset(&OlePres, 0, sizeof(OlePres));
-        /* Do we have any metafile data to save */
-        if(dwDataLength > 0)
-        {
-            if(dwObjectType == OLECONVERT_LINK_TYPE)
-            {
-                memcpy(OlePres.byUnknown1, pOlePresStreamLinkHeader, sizeof(pOlePresStreamLinkHeader));
-                nHeaderSize = sizeof(pOlePresStreamLinkHeader);
-            }
-            else
-            {
-                memcpy(OlePres.byUnknown1, pOlePresStreamEmbeddedHeader, sizeof(pOlePresStreamEmbeddedHeader));
-                nHeaderSize = sizeof(pOlePresStreamEmbeddedHeader);
-            }
-        }
-        else
-        {
-            memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
-            nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
-        }
-        /* Set width and height of the metafile */
-        OlePres.dwExtentX = dwExtentX;
-        OlePres.dwExtentY = -dwExtentY;
-
-        /* Set Data and Length */
-        if(dwDataLength > sizeof(METAFILEPICT16))
-        {
-            OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
-            OlePres.pData = &(pData[8]);
-        }
-        /* Save OlePres000 Data to Stream */
-        hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
-        hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
-        hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
-        hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
-        if(OlePres.dwSize > 0)
-        {
-            hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
-        }
-        IStream_Release(pStream);
-    }
-}
-
-/*************************************************************************
- * OLECONVERT_CreateOle10NativeStream [Internal] 
- *
- * Creates the "\001Ole10Native" Stream (should contain a BMP)
- *
- * PARAMS
- *     pStorage     [I] Dest storage to create the stream in
- *     pData        [I] Ole10 Native Data (ex. bmp)
- *     dwDataLength [I] Size of the Ole10 Native Data
- *
- * RETURNS
- *     Nothing
- *
- * NOTES
- *     This function is used by OleConvertOLESTREAMToIStorage only.
- *
- *     Might need to verify the data and return appropriate error message
- *     
- */
-void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
-{
-    HRESULT hRes;
-    IStream *pStream;
-    WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
-    
-    /* Create the Ole10Native Stream */
-    hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
-        STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
-
-    if(hRes == S_OK)
-    {
-        /* Write info to stream */
-        hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
-        hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
-        IStream_Release(pStream);
-    }
-
-}
-
-/*************************************************************************
- * OLECONVERT_GetProgIDFromStorage [Internal] 
- *
- * Finds the ProgID (or OleTypeID) from the IStorage
- *
- * PARAMS
- *     pStorage        [I] The Src IStorage to get the ProgID
- *     strProgID       [I] the ProgID string to get
- *     dwSize          [I] the size of the string
- *
- * RETURNS
- *     Success:  S_OK
- *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
- *
- * NOTES
- *     This function is used by OleConvertIStorageToOLESTREAM only.
- *
- *     
- */
-HRESULT OLECONVERT_GetProgIDFromStorage(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
-{
-    HRESULT hRes;
-    IStream *pStream;
-    LARGE_INTEGER iSeekPos;
-
-    strProgID[0] = NULL;
-    
-    if(strProgID == NULL || dwSize == NULL)
-    {
-        return E_INVALIDARG;
-    }
-
-    if(OLECONVERT_IsStorageLink(pStorage))
-    {
-        LPOLESTR wstrProgID;
-        WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
-
-        /* Open the CompObj Stream */
-        hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
-            STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
-        if(hRes == S_OK)
-        {
-            OLECONVERT_ISTORAGE_OLE OleStreamHeader;
-
-            /* Get the CLSID Offset */
-            iSeekPos.LowPart = sizeof(OleStreamHeader.dwOLEHEADER_ID) + sizeof(OleStreamHeader.dwUnknown1)
-                                + sizeof(OleStreamHeader.dwUnknown2) + sizeof(OleStreamHeader.dwUnknown3) 
-                                + sizeof(OleStreamHeader.dwUnknown4) + sizeof(OleStreamHeader.dwUnknown5);
-            iSeekPos.HighPart = 0;
-            hRes = IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
-            if(hRes == S_OK)
-            {
-                hRes = IStream_Read(pStream, &OleStreamHeader.dwObjectCLSIDOffset, sizeof(OleStreamHeader.dwObjectCLSIDOffset), NULL);
-            }
-            if(hRes == S_OK)
-            {
-                iSeekPos.LowPart = OleStreamHeader.dwObjectCLSIDOffset;
-                hRes = IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR, NULL);
-            }
-            /* Read the CLSID */
-            hRes = ReadClassStm(pStream, &OleStreamHeader.clsidObject);
-            if(hRes == S_OK)
-            {
-                hRes = ProgIDFromCLSID(&(OleStreamHeader.clsidObject), &wstrProgID);
-                if(hRes == S_OK)
-                {
-                    *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
-                }
-            }
-            IStream_Release(pStream);
-        }
-    }
-    else
-    {
-        
-        STATSTG stat;
-        OLECONVERT_ISTORAGE_COMPOBJ CompObj;
-        WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
-        /* Open the CompObj Stream */
-        hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
-            STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
-
-        if(hRes == S_OK)
-        {
-
-            /*Get the OleType from the CompObj Stream */
-            iSeekPos.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
-            iSeekPos.HighPart = 0;
-
-            hRes = IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
-            if(hRes == S_OK)
-            {
-                hRes = IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
-            }
-
-            if(hRes == S_OK)
-            {
-                iSeekPos.LowPart = CompObj.dwCLSIDNameLength;
-                hRes = IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
-            }
-            if(hRes == S_OK)
-            {
-                hRes = IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
-            }
-            if(hRes == S_OK)
-            {
-                iSeekPos.LowPart = CompObj.dwOleTypeNameLength;
-                hRes = IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
-            }
-
-            if(hRes == S_OK)
-            {
-                hRes = IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
-                if(*dwSize > 0)
-                {
-                    if(hRes == S_OK)
-                    {
-                        hRes = IStream_Read(pStream, strProgID, *dwSize, NULL);
-                    }
-                }
-            }
-            IStream_Release(pStream);
-        }
-
-        /* If the CompObject is not present, or there was an error reading the CompObject */
-        /* Get the CLSID from the storage stat */
-        if(hRes != S_OK)
-        {
-            LPOLESTR wstrProgID;
-
-            /* Get the OleType from the registry */
-            IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
-            hRes = ProgIDFromCLSID(&(stat.clsid), &wstrProgID);
-            if(hRes == S_OK)
-            {
-                *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
-            }
-        }
-    }
-    if(strProgID[0] == NULL)
-    {
-        *dwSize = 0;
-    }
-    return hRes;
-}
-
-/*************************************************************************
- * OLECONVERT_GetOle20PresData[Internal] 
- *
- * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
- *
- * PARAMS
- *     pStorage         [I] Src IStroage
- *     pOleStreamData   [I] Dest OleStream Mem Struct
- *
- * RETURNS
- *     Nothing
- *
- * NOTES
- *     This function is used by OleConvertIStorageToOLESTREAM only.
- *     
- *     Memory allocated for pData must be freed by the caller
- */
-void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
-{
-    HRESULT hRes;
-    IStream *pStream;
-    OLECONVERT_ISTORAGE_OLEPRES olePress;
-    WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
-
- 
-
-    /* Open OlePress000 stream */
-    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
-        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
-    if(hRes == S_OK)
-    {
-        LARGE_INTEGER iSeekPos;
-        METAFILEPICT16 MetaFilePict;
-        char strMetafilePictName[] = "METAFILEPICT";
-
-        /* Set the TypeID for a Metafile */
-        pOleStreamData[1].dwObjectTypeID = OLECONVERT_PRESENTATION_DATA_TYPE;
-
-        /* Set the OleTypeName to Metafile */
-        pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
-        strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
-
-        iSeekPos.HighPart = 0;
-        iSeekPos.LowPart = sizeof(olePress.byUnknown1);
-
-        /* Get Presentation Data */
-        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
-        IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
-        IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
-        IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
-
-        /*Set width and Height */
-        pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
-        pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
-        if(olePress.dwSize > 0)
-        {
-            /* Set Length */
-            pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
-
-            /* Set MetaFilePict struct */
-            MetaFilePict.mm = 8;
-            MetaFilePict.xExt = olePress.dwExtentX;
-            MetaFilePict.yExt = olePress.dwExtentY;
-            MetaFilePict.hMF = 0;
-
-            /* Get Metafile Data */
-            pOleStreamData[1].pData = (BYTE *) malloc(pOleStreamData[1].dwDataLength);
-            memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
-            IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
-        }
-        IStream_Release(pStream);
-    }
-}
-
-LPMONIKER OLECONVERT_LoadMonikers(CLSID *pclsid, IStream *pStream )
-{
-
-    LPMONIKER pDestMoniker=NULL;
-    HRESULT hRes;
-    if(IsEqualCLSID(&CLSID_FileMoniker, pclsid))
-    {
-        WCHAR temp=0;
-        hRes = CreateFileMoniker(&temp, &pDestMoniker);
-        IMoniker_Load(pDestMoniker, pStream);
-    }
-    else if(IsEqualCLSID(&CLSID_ItemMoniker, pclsid))
-    {
-        WCHAR temp1=0;
-        WCHAR temp2=0;
-        hRes = CreateItemMoniker(&temp1, &temp2, &pDestMoniker);
-        IMoniker_Load(pDestMoniker, pStream);
-    }
-    else if(IsEqualCLSID(&CLSID_CompositeMoniker, pclsid))
-    {
-        /* Problem with Saving CompositeMoniker */
-        /* TODO: Rechange remove code, create an empty CompositeMoniker */
-        WCHAR temp1=0;
-        WCHAR temp2=0;
-        LPMONIKER pItemMoniker, pFileMoniker;
-        hRes = CreateItemMoniker(&temp1, &temp2, &pItemMoniker);
-        hRes = CreateFileMoniker(&temp1, &pFileMoniker);
-        hRes = CreateGenericComposite(pFileMoniker, pItemMoniker, &pDestMoniker);
-        IMoniker_Load(pDestMoniker, pStream);
-    }
-    else
-    {
-        FIXME("Unsupported moniker in IStorage, /001Ole stream\n");
-    }
-    return pDestMoniker;
-}
-
-HRESULT OLECONVERT_GetMonikerFromStorage(LPSTORAGE pStorage, 
-    BYTE **pLinkFileName, DWORD* dwLinkFileNameLength, 
-    BYTE **pLinkExtraInfo,  DWORD* dwLinkExtraInfoLength)
-{
-    HRESULT hRes;
-    IStream *pStream;
-    WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
-    OLECONVERT_ISTORAGE_OLE OleStreamHeader;
-    LPMONIKER pDestMoniker=NULL;
-
-    *pLinkFileName = NULL;
-    *pLinkExtraInfo = NULL;
-    *dwLinkFileNameLength = 0;
-    *dwLinkExtraInfoLength = 0;
-
-    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
-        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
-
-    if(hRes == S_OK)
-    {   
-        /* Write default Data */
-        IStream_Read(pStream, &(OleStreamHeader.dwOLEHEADER_ID), sizeof(OleStreamHeader.dwOLEHEADER_ID), NULL);
-        IStream_Read(pStream, &(OleStreamHeader.dwUnknown1), sizeof(OleStreamHeader.dwUnknown1), NULL);
-        IStream_Read(pStream, &(OleStreamHeader.dwUnknown2), sizeof(OleStreamHeader.dwUnknown2), NULL);
-        IStream_Read(pStream, &(OleStreamHeader.dwUnknown3), sizeof(OleStreamHeader.dwUnknown3), NULL);
-        IStream_Read(pStream, &(OleStreamHeader.dwUnknown4), sizeof(OleStreamHeader.dwUnknown4), NULL);
-        IStream_Read(pStream, &(OleStreamHeader.dwUnknown5), sizeof(OleStreamHeader.dwUnknown5), NULL);
-        IStream_Read(pStream, &(OleStreamHeader.dwObjectCLSIDOffset), sizeof(OleStreamHeader.dwObjectCLSIDOffset), NULL);
-
-        /* Should call OleLoadFromStream, but implementeation incomplete */
-        ReadClassStm(pStream, &(OleStreamHeader.clsidMonikerTypeID));
-        /* Load the moniker */
-        pDestMoniker = OLECONVERT_LoadMonikers(&(OleStreamHeader.clsidMonikerTypeID), pStream);
-
-        /* Retreive the neccesary data */
-        if(IsEqualCLSID(&CLSID_FileMoniker, &(OleStreamHeader.clsidMonikerTypeID)))
-        {
-            
-            LPOLESTR ppszDisplayName;
-            IMoniker_GetDisplayName(pDestMoniker, NULL, NULL, &ppszDisplayName);
-            *dwLinkFileNameLength = WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
-                                        NULL, 0, NULL, FALSE);
-            *pLinkFileName = (BYTE *) malloc(*dwLinkFileNameLength);
-            WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
-                (LPSTR)*pLinkFileName, *dwLinkFileNameLength, NULL, FALSE);
-            CoTaskMemFree(ppszDisplayName);
-        }
-        else if(IsEqualCLSID(&CLSID_ItemMoniker, &(OleStreamHeader.clsidMonikerTypeID)))
-        {
-            LPOLESTR ppszDisplayName;
-            IMoniker_GetDisplayName(pDestMoniker, NULL, NULL, &ppszDisplayName);
-            *dwLinkExtraInfoLength = WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
-                                        NULL, 0, NULL, FALSE);
-            *pLinkExtraInfo = (BYTE *) malloc(*dwLinkExtraInfoLength);
-            WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
-                (LPSTR)*pLinkExtraInfo, *dwLinkExtraInfoLength, NULL, FALSE);
-            CoTaskMemFree(ppszDisplayName);
-            
-        }
-        else if(IsEqualCLSID(&CLSID_CompositeMoniker, &(OleStreamHeader.clsidMonikerTypeID)))
-        {
-            LPOLESTR ppszDisplayName;
-            IMoniker *pmk;
-            IEnumMoniker *enumMk;
-
-            IMoniker_Enum(pDestMoniker,TRUE,&enumMk);
-            IEnumMoniker_Next(enumMk,1,&pmk,NULL);
-            
-
-            IMoniker_GetDisplayName(pDestMoniker, NULL, NULL, &ppszDisplayName);
-            *dwLinkFileNameLength = WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
-                                        NULL, 0, NULL, FALSE);
-            *pLinkFileName = (BYTE *) malloc(*dwLinkFileNameLength);
-            WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
-                (LPSTR)*pLinkFileName, *dwLinkFileNameLength, NULL, FALSE);
-            CoTaskMemFree(ppszDisplayName);
-            IMoniker_Release(pmk);
-
-            IEnumMoniker_Next(enumMk,1,&pmk,NULL);
-
-            IMoniker_GetDisplayName(pDestMoniker, NULL, NULL, &ppszDisplayName);
-            *dwLinkExtraInfoLength = WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
-                                        NULL, 0, NULL, FALSE);
-            *pLinkExtraInfo = (BYTE *) malloc(*dwLinkExtraInfoLength);
-            WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
-                (LPSTR)*pLinkExtraInfo, *dwLinkExtraInfoLength, NULL, FALSE);
-            CoTaskMemFree(ppszDisplayName);
-            IMoniker_Release(pmk);
-            IEnumMoniker_Release(enumMk);
-        }
-        IStream_Read(pStream, &(OleStreamHeader.dwUnknown6), sizeof(OleStreamHeader.dwUnknown6), NULL);
-
-        ReadClassStm(pStream, &(OleStreamHeader.clsidObject));
-        IStream_Read(pStream, OleStreamHeader.dwUnknown7, sizeof(OleStreamHeader.dwUnknown7), NULL);
-        IStream_Release(pStream);
-    }
-    if(pDestMoniker != NULL)
-    {
-        IMoniker_Release(pDestMoniker);
-    }
-    return S_OK;
-
-
-}
-/*************************************************************************
- * OLECONVERT_SetEmbeddedOle10OLESTREAMData [Internal] 
- *
- * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
- *
- * PARAMS
- *     pStorage     [I] Src IStroage
- *     pOleStream   [I] Dest OleStream Mem Struct
- *
- * RETURNS
- *     Nothing
- *
- * NOTES
- *     This function is used by OleConvertIStorageToOLESTREAM only.
- *
- *     Memory allocated for pData must be freed by the caller
- *      
- *     
- */
-HRESULT OLECONVERT_SetEmbeddedOle10OLESTREAMData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
-{
-
-    HRESULT hRes;
-    IStream *pStream;
-    WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
-
-    /* Initialize Default data for OLESTREAM */
-    memset(pOleStreamData,0, sizeof(OLECONVERT_OLESTREAM_DATA) * OLECONVERT_NUM_OLE10STREAMS);
-    /* Get the ProgID */
-    pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
-    hRes = OLECONVERT_GetProgIDFromStorage(pStorage, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
-
-    if(hRes != S_OK)
-    {
-        /* Cannot find the CLSID in the registry. Abort! */
-        return hRes;
-    }
-
-    pOleStreamData[0].dwOleID = OLESTREAM_ID;
-    pOleStreamData[0].dwObjectTypeID = OLECONVERT_EMBEDDED_TYPE;
-
-    /* Open Ole10Native Stream */
-    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
-        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
-    if(hRes == S_OK)
-    {
-
-        /* Read Size and Data */
-        IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
-        if(pOleStreamData->dwDataLength > 0)
-        {
-            pOleStreamData->pData = (BYTE *) malloc(pOleStreamData->dwDataLength);
-            IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
-        }
-        IStream_Release(pStream);
-    }
-
-    if(hRes == S_OK)
-    {
-        /* Stream doens't exist for all cases: no stream for pbrush but package does! */
-        /* Cannot check for return value because the stream might not exist (normal behavior)*/
-        pOleStreamData[1].dwOleID = OLESTREAM_ID;
-        OLECONVERT_GetOle20PresData(pStorage, pOleStreamData);
-    }
-
-    return hRes;
-
-}
-
-HRESULT OLECONVERT_SetEmbeddedOle20OLESTREAMData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
-{
-
-    HRESULT hRes=S_OK;
-   /* Initialize Default data for OLESTREAM */
-    memset(pOleStreamData,0, sizeof(OLECONVERT_OLESTREAM_DATA) * OLECONVERT_NUM_OLE10STREAMS);
-
-    /* Get the ProgID */
-    pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
-    hRes = OLECONVERT_GetProgIDFromStorage(pStorage, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
-
-    if(hRes != S_OK)
-    {
-        /* Cannot find the CLSID in the registry. Abort! */
-        return hRes;
-    }
-
-    pOleStreamData[0].dwOleID = OLESTREAM_ID;
-    pOleStreamData[0].dwObjectTypeID = OLECONVERT_EMBEDDED_TYPE;
-    pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, 
-                                        &(pOleStreamData[0].pData));
-    pOleStreamData[1].dwOleID = OLESTREAM_ID;
-    OLECONVERT_GetOle20PresData(pStorage, pOleStreamData);
-
-    return hRes;
-}
-
-
-HRESULT OLECONVERT_SetLinkOLESTREAMData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
-{
-
-    HRESULT hRes = S_OK;
-   /* Initialize Default data for OLESTREAM */
-    memset(pOleStreamData,0, sizeof(OLECONVERT_OLESTREAM_DATA) * OLECONVERT_NUM_OLE10STREAMS);
-
-    /* Get the ProgID */
-    pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
-    hRes = OLECONVERT_GetProgIDFromStorage(pStorage, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
-
-    if(hRes != S_OK)
-    {
-        /* Cannot find the CLSID in the registry. Abort! */
-        return hRes;
-    }
-    pOleStreamData[0].dwOleID = OLESTREAM_ID;
-    pOleStreamData[0].dwObjectTypeID = OLECONVERT_LINK_TYPE;
-    /* TODO: Write the Link data */
-    OLECONVERT_GetMonikerFromStorage(pStorage, 
-        &(pOleStreamData[0].strLinkFileName), &(pOleStreamData[0].dwLinkFileNameLength), 
-        &(pOleStreamData[0].pLinkExtraInfo),  &(pOleStreamData[0].dwLinkExtraInfoLength));
-
-/*    pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData)); */
-    pOleStreamData[1].dwOleID = OLESTREAM_ID;
-    OLECONVERT_GetOle20PresData(pStorage, pOleStreamData);
-    return hRes;
-}
-
-
-HRESULT OLECONVERT_CreateEmbeddedIStorage(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
-{
-    HRESULT hRes = S_OK;
-    BOOL bCreateOle10Native = TRUE;
-    if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
-    {
-        /* Do we have the IStorage Data in the OLESTREAM */
-        if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
-        {
-            OLECONVERT_GetOLE20FromOLE10(pStorage, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
-            
-            OLECONVERT_CreateOlePresStream(pStorage, OLECONVERT_EMBEDDED_TYPE,
-                pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, 
-                pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
-            bCreateOle10Native = FALSE;
-        }
-    }
-
-    if(bCreateOle10Native)
-    {
-        /* It must be an original OLE 1.0 source */
-        OLECONVERT_CreateOle10NativeStream(pStorage, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
-
-        if(pOleStreamData[1].dwObjectTypeID == OLECONVERT_PRESENTATION_DATA_TYPE)
-        {
-            OLECONVERT_CreateOlePresStream(pStorage, OLECONVERT_EMBEDDED_TYPE, 
-                pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, 
-                pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
-        }
-    }
-
-    /*Create the Ole Stream if necessary */
-    OLECONVERT_CreateEmbeddedOleStream(pStorage);
-    /* Create CompObj Stream if necessary */
-    hRes = OLECONVERT_CreateCompObjStream(pStorage, pOleStreamData[0].strOleTypeName);
-    if(hRes == S_OK)
-    {
-        CLSID clsid;
-        
-        CLSIDFromProgID16(pOleStreamData[0].strOleTypeName, &clsid);
-        IStorage_SetClass(pStorage, &clsid);
-    }
-    return hRes;
-}
-
-HRESULT OLECONVERT_CreateLinkIStorage(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
-{
-    HRESULT hRes;
-    hRes = OLECONVERT_CreateLinkOleStream(pStorage, 
-        pOleStreamData[0].strOleTypeName, (LPCSTR)pOleStreamData[0].strLinkFileName, 
-        pOleStreamData[0].pLinkExtraInfo, pOleStreamData[0].dwLinkExtraInfoLength);
-    if(hRes == S_OK)
-    {
-        OLECONVERT_CreateOlePresStream(pStorage, OLECONVERT_LINK_TYPE,
-            pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, 
-            pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
-    }
-    if(hRes == S_OK)
-    {
-        IStorage_SetClass(pStorage, &IID_StdOleLink);
-    }
-    return hRes;
-}
-
-
-
-/*************************************************************************
- * OleConvertOLESTREAMToIStorage [OLE32.87] 
- *
- * Read info on MSDN
- *
- * TODO
- *      DVTARGETDEVICE paramenter is not handled
- *      Still unsure of some mem fields for OLE 10 Stream
- *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
- *      and "\001OLE" streams
- *     
- */
-HRESULT WINAPI OleConvertOLESTREAMToIStorage (
-    LPOLESTREAM pOleStream, 
-    LPSTORAGE pstg, 
-    const DVTARGETDEVICE* ptd)
-{
-    int i;
-    HRESULT hRes=S_OK;
-    OLECONVERT_OLESTREAM_DATA pOleStreamData[OLECONVERT_NUM_OLE10STREAMS];
-
-    memset(pOleStreamData, 0, sizeof(pOleStreamData));
-
-    if(ptd != NULL)
-    {
-        FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
-    }
-
-    if(pstg == NULL || pOleStream == NULL)
-    {
-        hRes = E_INVALIDARG;
-    }
-
-    if(hRes == S_OK)
-    {
-        /* Load the OLESTREAM to Memory */
-        hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0]);
-    }
-
-    if(hRes == S_OK)
-    {
-        /* Load the OLESTREAM to Memory (part 2)*/
-        hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1]);
-    }
-
-    if(hRes == S_OK)
-    {
-        /* Is olestream an embedded object */
-        if(pOleStreamData[0].dwObjectTypeID != OLECONVERT_LINK_TYPE)
-        {
-            hRes = OLECONVERT_CreateEmbeddedIStorage(pstg, pOleStreamData);
-        }
-        else
-        {
-            hRes = OLECONVERT_CreateLinkIStorage(pstg, pOleStreamData);
-        }
-    }
-    /* Free allocated memory */
-    for(i=0; i < OLECONVERT_NUM_OLE10STREAMS; i++)
-    {
-        if(pOleStreamData[i].pData != NULL)
-        {
-            free(pOleStreamData[i].pData);
-        }
-
-        if(pOleStreamData[i].pLinkExtraInfo != NULL)
-        {
-            free(pOleStreamData[i].pLinkExtraInfo);
-        }
-        if(pOleStreamData[i].strLinkFileName != NULL)
-        {
-            free(pOleStreamData[i].strLinkFileName);
-        }
-    }
-    return hRes;
-}
-
-/*************************************************************************
- * OleConvertIStorageToOLESTREAM [OLE32.85]
- *
- * Read info on MSDN
- *
- * Read info on MSDN
- *
- * TODO
- *      Still unsure of some mem fields for OLE 10 Stream
- *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
- *      and "\001OLE" streams.
- *     
- */
-HRESULT WINAPI OleConvertIStorageToOLESTREAM (
-    LPSTORAGE pstg, 
-    LPOLESTREAM pOleStream)
-{
-    int i;
-    HRESULT hRes = S_OK;
-    IStream *pStream;
-    OLECONVERT_OLESTREAM_DATA pOleStreamData[OLECONVERT_NUM_OLE10STREAMS];
-    WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
-
-
-    memset(pOleStreamData, 0, sizeof(pOleStreamData));
-
-    if(pstg == NULL || pOleStream == NULL)
-    {
-        hRes = E_INVALIDARG;
-    }
-    if(hRes == S_OK)
-    {
-        if(!OLECONVERT_IsStorageLink(pstg))
-        {
-            /*Was it originaly Ole10 */
-            hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);    
-            if(hRes == S_OK)
-            {
-                IStream_Release(pStream);
-                /*Get Presentation Data for Ole10Native */
-                hRes = OLECONVERT_SetEmbeddedOle10OLESTREAMData(pstg, pOleStreamData);
-            }
-            else
-            {
-                /*Get Presentation Data (OLE20)*/
-                hRes = OLECONVERT_SetEmbeddedOle20OLESTREAMData(pstg, pOleStreamData);
-            }
-        }
-        else
-        {
-            hRes = OLECONVERT_SetLinkOLESTREAMData(pstg, pOleStreamData);
-        }
-
-        if(hRes == S_OK)
-        {
-            /* Save OLESTREAM */
-            hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
-            if(hRes == S_OK)
-            {
-                hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
-            }
-        }
-    }
-
-    /* Free allocated memory */
-    for(i=0; i < OLECONVERT_NUM_OLE10STREAMS; i++)
-    {
-        if(pOleStreamData[i].pData != NULL)
-        {
-            free(pOleStreamData[i].pData);
-        }
-
-        if(pOleStreamData[i].pLinkExtraInfo != NULL)
-        {
-            free(pOleStreamData[i].pLinkExtraInfo);
-        }
-
-        if(pOleStreamData[i].strLinkFileName != NULL)
-        {
-            free(pOleStreamData[i].strLinkFileName);
-        }
-    }
-
-    return hRes;
-}
-
-/******************************************************************************
- * StgIsStorageFile16 [STORAGE.5]
- */
-HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
-static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
-        HFILE           hf;
-        OFSTRUCT        ofs;
-        BYTE            magic[24];
-
-        TRACE_(ole)("(\'%s\')\n",fn);
-        hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
-        if (hf==HFILE_ERROR)
-                return STG_E_FILENOTFOUND;
-        if (24!=_lread(hf,magic,24)) {
-                WARN_(ole)(" too short\n");
-                _lclose(hf);
-                return S_FALSE;
-        }
-        if (!memcmp(magic,STORAGE_magic,8)) {
-                WARN_(ole)(" -> YES\n");
-                _lclose(hf);
-                return S_OK;
-        }
-        if (!memcmp(magic,STORAGE_notmagic,8)) {
-                WARN_(ole)(" -> NO\n");
-                _lclose(hf);
-                return S_FALSE;
-        }
-        if (!memcmp(magic,STORAGE_oldmagic,8)) {
-                WARN_(ole)(" -> old format\n");
-                _lclose(hf);
-                return STG_E_OLDFORMAT;
-        }
-        WARN_(ole)(" -> Invalid header.\n");
-        _lclose(hf);
-        return STG_E_INVALIDHEADER;
-}
-
-HRESULT WINAPI
-StgIsStorageFile(LPCOLESTR fn)
-{
-        LPOLESTR16      xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
-        HRESULT       ret = StgIsStorageFile16(xfn);
-
-        HeapFree(GetProcessHeap(),0,xfn);
-        return ret;
-}
-
Index: trunk/src/ole32/storage.h
===================================================================
--- trunk/src/ole32/storage.h	(revision 5024)
+++ 	(revision )
@@ -1,875 +1,0 @@
-/* $Id: storage.h,v 1.3 2000-09-17 10:29:44 davidr Exp $ */
-/*
- * Compound Storage (32 bit version)
- *
- * Implemented using the documentation of the LAOLA project at
- * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
- * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
- *
- * This include file contains definitions of types and function
- * prototypes that are used in the many files implementing the 
- * storage functionality
- *
- * Copyright 1998,1999 Francis Beaudet
- * Copyright 1998,1999 Thuy Nguyen
- */
-#ifndef __STORAGE32_H__
-#define __STORAGE32_H__
-
-#include "wtypes.h"
-#include "winnt.h"
-#include "wine/obj_storage.h"
-
-/*
- * Definitions for the file format offsets.
- */
-static const ULONG OFFSET_BIGBLOCKSIZEBITS   = 0x0000001e;
-static const ULONG OFFSET_SMALLBLOCKSIZEBITS = 0x00000020;
-static const ULONG OFFSET_BBDEPOTCOUNT	     = 0x0000002C;
-static const ULONG OFFSET_ROOTSTARTBLOCK     = 0x00000030;
-static const ULONG OFFSET_SBDEPOTSTART	     = 0x0000003C;
-static const ULONG OFFSET_EXTBBDEPOTSTART    = 0x00000044;
-static const ULONG OFFSET_EXTBBDEPOTCOUNT    = 0x00000048;
-static const ULONG OFFSET_BBDEPOTSTART	     = 0x0000004C;
-static const ULONG OFFSET_PS_NAME            = 0x00000000;
-static const ULONG OFFSET_PS_NAMELENGTH	     = 0x00000040;
-static const ULONG OFFSET_PS_PROPERTYTYPE    = 0x00000042;
-static const ULONG OFFSET_PS_PREVIOUSPROP    = 0x00000044;
-static const ULONG OFFSET_PS_NEXTPROP        = 0x00000048;   
-static const ULONG OFFSET_PS_DIRPROP	     = 0x0000004C;
-static const ULONG OFFSET_PS_GUID            = 0x00000050;
-static const ULONG OFFSET_PS_TSS1	     = 0x00000064;
-static const ULONG OFFSET_PS_TSD1            = 0x00000068;
-static const ULONG OFFSET_PS_TSS2            = 0x0000006C;
-static const ULONG OFFSET_PS_TSD2            = 0x00000070;
-static const ULONG OFFSET_PS_STARTBLOCK	     = 0x00000074; 
-static const ULONG OFFSET_PS_SIZE	     = 0x00000078; 
-static const WORD  DEF_BIG_BLOCK_SIZE_BITS   = 0x0009;
-static const WORD  DEF_SMALL_BLOCK_SIZE_BITS = 0x0006;
-static const WORD  DEF_BIG_BLOCK_SIZE        = 0x0200;
-static const WORD  DEF_SMALL_BLOCK_SIZE      = 0x0040;
-static const ULONG BLOCK_EXTBBDEPOT          = 0xFFFFFFFC;
-static const ULONG BLOCK_SPECIAL             = 0xFFFFFFFD;
-static const ULONG BLOCK_END_OF_CHAIN        = 0xFFFFFFFE;
-static const ULONG BLOCK_UNUSED              = 0xFFFFFFFF;
-static const ULONG PROPERTY_NULL             = 0xFFFFFFFF;
-
-#define PROPERTY_NAME_MAX_LEN    0x20
-#define PROPERTY_NAME_BUFFER_LEN 0x40             
-
-#define PROPSET_BLOCK_SIZE 0x00000080
-
-/*
- * Property type of relation
- */
-#define PROPERTY_RELATION_PREVIOUS 0
-#define PROPERTY_RELATION_NEXT     1
-#define PROPERTY_RELATION_DIR      2
-
-/*
- * Property type constants
- */
-#define PROPTYPE_STORAGE 0x01
-#define PROPTYPE_STREAM  0x02
-#define PROPTYPE_ROOT    0x05
-
-/*
- * These defines assume a hardcoded blocksize. The code will assert
- * if the blocksize is different. Some changes will have to be done if it
- * becomes the case.
- */
-#define BIG_BLOCK_SIZE           0x200
-#define COUNT_BBDEPOTINHEADER    109
-#define LIMIT_TO_USE_SMALL_BLOCK 0x1000
-#define NUM_BLOCKS_PER_DEPOT_BLOCK 128
-
-/*
- * 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};
-
-/*
- * Forward declarations of all the structures used by the storage
- * module.
- */
-typedef struct StorageBaseImpl     StorageBaseImpl;
-typedef struct StorageImpl         StorageImpl;
-typedef struct StorageInternalImpl StorageInternalImpl;
-typedef struct BlockChainStream      BlockChainStream;
-typedef struct SmallBlockChainStream SmallBlockChainStream;
-typedef struct IEnumSTATSTGImpl      IEnumSTATSTGImpl;
-typedef struct StgProperty           StgProperty;
-typedef struct StgStreamImpl         StgStreamImpl;
-
-/*
- * This utility structure is used to read/write the information in a storage
- * property.
- */
-struct StgProperty
-{
-  WCHAR	         name[PROPERTY_NAME_MAX_LEN];
-  WORD	         sizeOfNameString;
-  BYTE	         propertyType;
-  ULONG	         previousProperty;
-  ULONG	         nextProperty;
-  ULONG          dirProperty;
-  GUID           propertyUniqueID;
-  ULONG          timeStampS1;
-  ULONG          timeStampD1;
-  ULONG          timeStampS2;
-  ULONG          timeStampD2;
-  ULONG          startingBlock;
-  ULARGE_INTEGER size;
-};
-
-/*************************************************************************
- * Big Block File support
- *
- * The big block file is an abstraction of a flat file separated in
- * same sized blocks. The implementation for the methods described in 
- * this section appear in stg_bigblockfile.c
- */
-
-/*
- * Declaration of the data structures
- */
-typedef struct BigBlockFile BigBlockFile,*LPBIGBLOCKFILE;
-typedef struct MappedPage   MappedPage,*LPMAPPEDPAGE;
-
-struct BigBlockFile
-{
-  BOOL fileBased;
-  ULARGE_INTEGER filesize;
-  ULONG blocksize;
-  HANDLE hfile;
-  HANDLE hfilemap;
-  DWORD flProtect;
-  MappedPage *maplist;
-  MappedPage *victimhead, *victimtail;
-  ULONG num_victim_pages;
-  ILockBytes *pLkbyt;
-  HGLOBAL hbytearray;
-  LPVOID pbytearray;
-};
-
-/*
- * Declaration of the functions used to manipulate the BigBlockFile
- * data structure.
- */
-BigBlockFile*  BIGBLOCKFILE_Construct(HANDLE hFile,
-                                      ILockBytes* pLkByt,
-                                      DWORD openFlags,
-                                      ULONG blocksize,
-                                      BOOL fileBased);
-void           BIGBLOCKFILE_Destructor(LPBIGBLOCKFILE This);
-void*          BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index);
-void*          BIGBLOCKFILE_GetROBigBlock(LPBIGBLOCKFILE This, ULONG index);
-void           BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock);
-void           BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize);
-ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This);
-
-/****************************************************************************
- * Storage32BaseImpl definitions.
- *
- * This stucture defines the base information contained in all implementations
- * of IStorage32 contained in this filee storage implementation.
- *
- * In OOP terms, this is the base class for all the IStorage32 implementations
- * contained in this file.
- */
-struct StorageBaseImpl
-{
-  ICOM_VFIELD(IStorage);   /* Needs to be the first item in the stuct
-			    * since we want to cast this in a Storage32 pointer */
-
-  /*
-   * Reference count of this object
-   */
-  ULONG ref;
-  
-  /* 
-   * Ancestor storage (top level) 
-   */
-  StorageImpl* ancestorStorage;		 
-  
-  /*
-   * Index of the property for the root of
-   * this storage
-   */
-  ULONG rootPropertySetIndex;
-  
-  /* 
-   * virtual Destructor method.
-   */
-  void (*v_destructor)(StorageBaseImpl*);
-};
-
-
-/*
- * Prototypes for the methods of the Storage32BaseImpl class.
- */
-HRESULT WINAPI StorageBaseImpl_QueryInterface(
-            IStorage*        iface,
-            REFIID             riid,
-            void**             ppvObject);
-        
-ULONG WINAPI StorageBaseImpl_AddRef( 
-            IStorage*        iface);
-        
-ULONG WINAPI StorageBaseImpl_Release( 
-            IStorage*        iface);
-        
-HRESULT WINAPI StorageBaseImpl_OpenStream( 
-            IStorage*        iface,
-            const OLECHAR*   pwcsName,  /* [string][in] */
-            void*              reserved1, /* [unique][in] */
-            DWORD              grfMode,   /* [in] */        
-            DWORD              reserved2, /* [in] */        
-            IStream**        ppstm);    /* [out] */   
-    
-HRESULT WINAPI StorageBaseImpl_OpenStorage( 
-            IStorage*        iface,
-            const OLECHAR*   pwcsName,      /* [string][unique][in] */ 
-            IStorage*        pstgPriority,  /* [unique][in] */         
-            DWORD              grfMode,       /* [in] */                 
-            SNB              snbExclude,    /* [unique][in] */         
-            DWORD              reserved,      /* [in] */                 
-            IStorage**       ppstg);        /* [out] */                
-          
-HRESULT WINAPI StorageBaseImpl_EnumElements( 
-            IStorage*        iface,
-            DWORD              reserved1, /* [in] */                  
-            void*              reserved2, /* [size_is][unique][in] */ 
-            DWORD              reserved3, /* [in] */                  
-            IEnumSTATSTG**     ppenum);   /* [out] */   
-
-HRESULT WINAPI StorageBaseImpl_Stat( 
-            IStorage*        iface,
-            STATSTG*           pstatstg,     /* [out] */ 
-            DWORD              grfStatFlag); /* [in] */  
-
-HRESULT WINAPI StorageBaseImpl_RenameElement(
-            IStorage*        iface,
-            const OLECHAR*   pwcsOldName,  /* [string][in] */
-            const OLECHAR*   pwcsNewName); /* [string][in] */
-
-HRESULT WINAPI StorageBaseImpl_CreateStream(
-            IStorage*        iface,
-            const OLECHAR*   pwcsName,  /* [string][in] */
-            DWORD              grfMode,   /* [in] */
-            DWORD              reserved1, /* [in] */
-            DWORD              reserved2, /* [in] */
-            IStream**        ppstm);    /* [out] */
-
-HRESULT WINAPI StorageBaseImpl_SetClass(
-            IStorage*        iface,
-            REFCLSID           clsid);  /* [in] */
-
-/****************************************************************************
- * Storage32Impl definitions.
- *
- * This implementation of the IStorage32 interface represents a root
- * storage. Basically, a document file.
- */
-struct StorageImpl
-{
-  ICOM_VFIELD(IStorage);   /* Needs to be the first item in the stuct
-				      * since we want to cast this in a Storage32 pointer */
-
-  /*
-   * Declare the member of the Storage32BaseImpl class to allow
-   * casting as a Storage32BaseImpl
-   */
-  ULONG		        ref;
-  struct StorageImpl* ancestorStorage;		 
-  ULONG                 rootPropertySetIndex;
-  void (*v_destructor)(struct StorageImpl*);
-  
-  /*
-   * The following data members are specific to the Storage32Impl
-   * class
-   */
-  HANDLE           hFile;      /* Physical support for the Docfile */
-  
-  /*
-   * File header
-   */
-  WORD  bigBlockSizeBits;
-  WORD  smallBlockSizeBits;
-  ULONG bigBlockSize;
-  ULONG smallBlockSize;
-  ULONG bigBlockDepotCount;
-  ULONG rootStartBlock;
-  ULONG smallBlockDepotStart;
-  ULONG extBigBlockDepotStart;
-  ULONG extBigBlockDepotCount;
-  ULONG bigBlockDepotStart[COUNT_BBDEPOTINHEADER];
-
-  ULONG blockDepotCached[NUM_BLOCKS_PER_DEPOT_BLOCK];
-  ULONG indexBlockDepotCached;
-  ULONG prevFreeBlock;
-
-  /*
-   * Abstraction of the big block chains for the chains of the header.
-   */
-  BlockChainStream* rootBlockChain;
-  BlockChainStream* smallBlockDepotChain;
-  BlockChainStream* smallBlockRootChain;  
-
-  /*
-   * Pointer to the big block file abstraction
-   */
-  BigBlockFile* bigBlockFile; 
-
-  /*****************************************************************************************/
-  /* warning: this is a temp fix for bugs related to save file to mounted network drive    */
-  /* TBD: these lines should be removed when we will get the final fix                     */
-  /*****************************************************************************************/
-  WCHAR* srcDestFiles[2];
-  /*****************************************************************************************/
-};
-
-/*
- * Method declaration for the Storage32Impl class
- */        
-
-HRESULT WINAPI StorageImpl_CreateStorage( 
-            IStorage*      iface,
-            const OLECHAR* pwcsName,  /* [string][in] */ 
-            DWORD            grfMode,   /* [in] */ 
-            DWORD            dwStgFmt,  /* [in] */ 
-            DWORD            reserved2, /* [in] */ 
-            IStorage**     ppstg);    /* [out] */ 
-        
-HRESULT WINAPI StorageImpl_CopyTo( 
-            IStorage*      iface,
-            DWORD          ciidExclude,  /* [in] */ 
-            const IID*     rgiidExclude, /* [size_is][unique][in] */ 
-            SNB            snbExclude, /* [unique][in] */ 
-            IStorage*    pstgDest);    /* [unique][in] */ 
-        
-HRESULT WINAPI StorageImpl_MoveElementTo( 
-            IStorage*      iface,
-            const OLECHAR* pwcsName,    /* [string][in] */ 
-            IStorage*      pstgDest,    /* [unique][in] */ 
-            const OLECHAR* pwcsNewName, /* [string][in] */ 
-            DWORD            grfFlags);   /* [in] */ 
-        
-HRESULT WINAPI StorageImpl_Commit( 
-            IStorage*      iface,
-            DWORD          grfCommitFlags); /* [in] */ 
-        
-HRESULT WINAPI StorageImpl_Revert( 
-            IStorage*      iface);
-        
-HRESULT WINAPI StorageImpl_DestroyElement( 
-            IStorage*      iface,
-            const OLECHAR* pwcsName); /* [string][in] */ 
-        
-HRESULT WINAPI StorageImpl_SetElementTimes( 
-            IStorage*      iface,
-            const OLECHAR* pwcsName, /* [string][in] */ 
-            const FILETIME*  pctime,   /* [in] */ 
-            const FILETIME*  patime,   /* [in] */ 
-            const FILETIME*  pmtime);  /* [in] */ 
-
-HRESULT WINAPI StorageImpl_SetStateBits( 
-            IStorage*      iface,
-            DWORD          grfStateBits, /* [in] */ 
-            DWORD          grfMask);     /* [in] */ 
-        
-void StorageImpl_Destroy(
-	    StorageImpl* This);
-
-HRESULT StorageImpl_Construct(
-            StorageImpl* This,
-            HANDLE       hFile,
-            ILockBytes*  pLkbyt,
-            DWORD        openFlags,
-            BOOL         fileBased,
-            BOOL         fileCreate);
-
-BOOL StorageImpl_ReadBigBlock(
-            StorageImpl* This,
-	    ULONG          blockIndex,
-	    void*          buffer);
-
-BOOL StorageImpl_WriteBigBlock(
-            StorageImpl* This,
-	    ULONG          blockIndex,
-	    void*          buffer);
-
-void* StorageImpl_GetROBigBlock(
-            StorageImpl* This,
-	    ULONG          blockIndex);
-
-void* StorageImpl_GetBigBlock(
-	    StorageImpl* This,
-	    ULONG          blockIndex);
-
-void StorageImpl_ReleaseBigBlock(
-            StorageImpl* This,
-            void*          pBigBlock);
-
-ULONG StorageImpl_GetNextFreeBigBlock(
-            StorageImpl* This);
-
-void StorageImpl_FreeBigBlock(
-            StorageImpl* This,
-	    ULONG blockIndex);
-
-ULONG StorageImpl_GetNextBlockInChain(
-            StorageImpl* This,
-	    ULONG blockIndex);
-
-void StorageImpl_SetNextBlockInChain(
-            StorageImpl* This,
-	    ULONG blockIndex,
-      ULONG nextBlock);
-
-HRESULT StorageImpl_LoadFileHeader(
-	    StorageImpl* This);
-
-void StorageImpl_SaveFileHeader(
-            StorageImpl* This);
-
-BOOL StorageImpl_ReadProperty(
-            StorageImpl* This,
-	    ULONG          index,
-	    StgProperty*    buffer);
-
-BOOL StorageImpl_WriteProperty(
-            StorageImpl* This,
-	    ULONG          index,
-	    StgProperty*   buffer);
-
-BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
-                      StorageImpl* This,
-                      SmallBlockChainStream** ppsbChain);
-
-ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This,
-                                         ULONG blockIndex);
-
-void Storage32Impl_AddBlockDepot(StorageImpl* This,
-                                 ULONG blockIndex);
-
-ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This);
-
-ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This,
-                                     ULONG depotIndex);
-
-void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
-                                    ULONG depotIndex,
-                                    ULONG blockIndex);
-/****************************************************************************
- * 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
-{
-  ICOM_VFIELD(IStorage);	/* Needs to be the first item in the stuct
-				 * since we want to cast this in a Storage32 pointer */
-
-  /*
-   * Declare the member of the Storage32BaseImpl class to allow
-   * casting as a Storage32BaseImpl
-   */
-  ULONG		             ref;
-  struct StorageImpl* ancestorStorage;		 
-  ULONG                    rootPropertySetIndex;
-  void (*v_destructor)(struct StorageInternalImpl*);
-
-  /*
-   * There is no specific data for this class.
-   */
-};
-
-/*
- * Method definitions for the Storage32InternalImpl class.
- */
-StorageInternalImpl* StorageInternalImpl_Construct(
-	    StorageImpl* ancestorStorage,	
-	    ULONG          rootTropertyIndex);
-
-void StorageInternalImpl_Destroy(
-       	    StorageInternalImpl* This);
-
-HRESULT WINAPI StorageInternalImpl_Commit( 
-	    IStorage*            iface,
-	    DWORD                  grfCommitFlags); /* [in] */ 
-
-HRESULT WINAPI StorageInternalImpl_Revert( 
-     	    IStorage*            iface);
-
-
-/****************************************************************************
- * 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.
- */
-struct IEnumSTATSTGImpl
-{
-  ICOM_VFIELD(IEnumSTATSTG);    /* Needs to be the first item in the stuct
-					 * since we want to cast this in a IEnumSTATSTG pointer */
-  
-  ULONG		 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
-};
-
-/*
- * Method definitions for the IEnumSTATSTGImpl class.
- */
-HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
-	    IEnumSTATSTG*     iface,
-	    REFIID            riid,
-	    void**            ppvObject);
-        
-ULONG WINAPI IEnumSTATSTGImpl_AddRef(
-            IEnumSTATSTG*     iface); 
-        
-ULONG WINAPI IEnumSTATSTGImpl_Release(
-            IEnumSTATSTG*     iface);
-        
-HRESULT WINAPI IEnumSTATSTGImpl_Next(
-            IEnumSTATSTG*     iface,
-	    ULONG             celt,
-	    STATSTG*          rgelt,
-	    ULONG*            pceltFetched);
-        
-HRESULT WINAPI IEnumSTATSTGImpl_Skip(
-            IEnumSTATSTG*     iface,
-	    ULONG             celt);
-        
-HRESULT WINAPI IEnumSTATSTGImpl_Reset(
-            IEnumSTATSTG* iface);
-        
-HRESULT WINAPI IEnumSTATSTGImpl_Clone(
-            IEnumSTATSTG*     iface,
-	    IEnumSTATSTG**    ppenum);
-
-IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
-            StorageImpl* This,
-	    ULONG          firstPropertyNode);
-
-void IEnumSTATSTGImpl_Destroy(
-            IEnumSTATSTGImpl* This);
-
-void IEnumSTATSTGImpl_PushSearchNode(
-	    IEnumSTATSTGImpl* This,
-	    ULONG             nodeToPush);
-
-ULONG IEnumSTATSTGImpl_PopSearchNode(
-            IEnumSTATSTGImpl* This,
-	    BOOL            remove);
-
-ULONG IEnumSTATSTGImpl_FindProperty(
-            IEnumSTATSTGImpl* This,
-	    const OLECHAR*  lpszPropName,
-	    StgProperty*      buffer);
-
-INT IEnumSTATSTGImpl_FindParentProperty(
-  IEnumSTATSTGImpl *This,
-  ULONG             childProperty,
-  StgProperty      *currentProperty,
-  ULONG            *propertyId);
-
-
-/****************************************************************************
- * StgStreamImpl definitions.
- *
- * This class imlements the IStream32 inteface and represents a stream
- * located inside a storage object.
- */
-struct StgStreamImpl
-{
-  ICOM_VFIELD(IStream);  /* Needs to be the first item in the stuct
-				    * since we want to cast this in a IStream pointer */
-  
-  /*
-   * Reference count
-   */
-  ULONG		     ref;
-
-  /*
-   * Storage that is the parent(owner) of the stream
-   */
-  StorageBaseImpl* parentStorage;
-
-  /*
-   * Access mode of this stream.
-   */
-  DWORD grfMode;
-
-  /*
-   * Index of the property that owns (points to) this stream.
-   */
-  ULONG              ownerProperty;
-
-  /*
-   * Helper variable that contains the size of the stream
-   */
-  ULARGE_INTEGER     streamSize;
-
-  /*
-   * This is the current position of the cursor in the stream
-   */
-  ULARGE_INTEGER     currentPosition;
-  
-  /*
-   * The information in the stream is represented by a chain of small blocks
-   * or a chain of large blocks. Depending on the case, one of the two
-   * following variabled points to that information.
-   */
-  BlockChainStream*      bigBlockChain;
-  SmallBlockChainStream* smallBlockChain;
-  
-};
-
-/*
- * Method definition for the StgStreamImpl class.
- */
-StgStreamImpl* StgStreamImpl_Construct(
-		StorageBaseImpl* parentStorage,
-    DWORD            grfMode,
-    ULONG            ownerProperty);
-
-void StgStreamImpl_Destroy(
-                StgStreamImpl* This);
-
-void StgStreamImpl_OpenBlockChain(
-                StgStreamImpl* This);
-
-HRESULT WINAPI StgStreamImpl_QueryInterface(
-		IStream*      iface,
-		REFIID         riid,		/* [in] */          
-		void**         ppvObject);  /* [iid_is][out] */ 
-        
-ULONG WINAPI StgStreamImpl_AddRef(
-		IStream*      iface);
-        
-ULONG WINAPI StgStreamImpl_Release(
-		IStream*      iface);
-        
-HRESULT WINAPI StgStreamImpl_Read( 
-	        IStream*      iface,
-		void*          pv,        /* [length_is][size_is][out] */
-		ULONG          cb,        /* [in] */                     
-		ULONG*         pcbRead);  /* [out] */                    
-        
-HRESULT WINAPI StgStreamImpl_Write(
-		IStream*      iface,
-		const void*    pv,          /* [size_is][in] */ 
-		ULONG          cb,          /* [in] */          
-		ULONG*         pcbWritten); /* [out] */         
-        
-HRESULT WINAPI StgStreamImpl_Seek( 
-		IStream*      iface,
-		LARGE_INTEGER   dlibMove,         /* [in] */ 
-		DWORD           dwOrigin,         /* [in] */ 
-		ULARGE_INTEGER* plibNewPosition); /* [out] */
-        
-HRESULT WINAPI StgStreamImpl_SetSize( 
-	        IStream*      iface,
-		ULARGE_INTEGER  libNewSize);  /* [in] */ 
-        
-HRESULT WINAPI StgStreamImpl_CopyTo( 
-		IStream*      iface,
-		IStream*      pstm,         /* [unique][in] */ 
-		ULARGE_INTEGER  cb,           /* [in] */         
-		ULARGE_INTEGER* pcbRead,      /* [out] */        
-		ULARGE_INTEGER* pcbWritten);  /* [out] */        
-
-HRESULT WINAPI StgStreamImpl_Commit( 
-	    	IStream*      iface,
-		DWORD           grfCommitFlags); /* [in] */ 
-        
-HRESULT WINAPI StgStreamImpl_Revert( 
-		IStream*  iface);
-        
-HRESULT WINAPI StgStreamImpl_LockRegion( 
-		IStream*     iface,
-		ULARGE_INTEGER libOffset,   /* [in] */ 
-		ULARGE_INTEGER cb,          /* [in] */ 
-		DWORD          dwLockType); /* [in] */ 
-        
-HRESULT WINAPI StgStreamImpl_UnlockRegion( 
-		IStream*     iface,
-		ULARGE_INTEGER libOffset,   /* [in] */ 
-	        ULARGE_INTEGER cb,          /* [in] */ 
-		DWORD          dwLockType); /* [in] */ 
-        
-HRESULT WINAPI StgStreamImpl_Stat( 
-		IStream*     iface,
-	        STATSTG*       pstatstg,     /* [out] */
-	        DWORD          grfStatFlag); /* [in] */ 
-        
-HRESULT WINAPI StgStreamImpl_Clone( 
-		IStream*     iface,
-		IStream**    ppstm);       /* [out] */ 
-
-
-/********************************************************************************
- * The StorageUtl_ functions are miscelaneous utility functions. Most of which are
- * abstractions used to read values from file buffers without having to worry 
- * about bit order
- */
-void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value);
-void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value);
-void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value);
-void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value);
-void StorageUtl_ReadDWords(void *buffer, ULONG offset, DWORD *values,
-			   ULONG len);
-void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value);
-void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value);
-void StorageUtl_CopyPropertyToSTATSTG(STATSTG*     destination,
-					     StgProperty* source,
-					     int          statFlags);
-
-/****************************************************************************
- * BlockChainStream definitions.
- *
- * The BlockChainStream class is a utility class that is used to create an
- * abstraction of the big block chains in the storage file.
- */
-struct BlockChainStream
-{
-  StorageImpl* parentStorage;
-  ULONG*       headOfStreamPlaceHolder;
-  ULONG        ownerPropertyIndex;
-  ULONG        lastBlockNoInSequence;
-  ULONG        lastBlockNoInSequenceIndex;
-  ULONG        tailIndex;
-  ULONG        numBlocks;
-  BOOL         lazyInitComplete;
-};
-
-/*
- * Methods for the BlockChainStream class.
- */
-BlockChainStream* BlockChainStream_Construct(
-		StorageImpl* parentStorage,	
-		ULONG*         headOfStreamPlaceHolder,
-		ULONG          propertyIndex);
-
-void BlockChainStream_Destroy(
-		BlockChainStream* This);
-
-ULONG BlockChainStream_GetHeadOfChain(
-		BlockChainStream* This);
-
-BOOL BlockChainStream_ReadAt(
-		BlockChainStream* This,
-		ULARGE_INTEGER offset,
-		ULONG          size,
-		void*          buffer,
-		ULONG*         bytesRead);
-
-BOOL BlockChainStream_WriteAt(
-		BlockChainStream* This,
-		ULARGE_INTEGER offset,
-		ULONG          size,
-		const void*    buffer,
-		ULONG*         bytesWritten);
-
-BOOL BlockChainStream_SetSize(
-		BlockChainStream* This,
-		ULARGE_INTEGER    newSize);
-
-ULARGE_INTEGER BlockChainStream_GetSize(
-    BlockChainStream* This);
-
-ULONG BlockChainStream_GetCount(
-    BlockChainStream* This);
-
-/****************************************************************************
- * SmallBlockChainStream definitions.
- *
- * The SmallBlockChainStream class is a utility class that is used to create an
- * abstraction of the small block chains in the storage file.
- */
-struct SmallBlockChainStream
-{
-  StorageImpl* parentStorage;
-  ULONG          ownerPropertyIndex;
-};
-
-/*
- * Methods of the SmallBlockChainStream class.
- */
-SmallBlockChainStream* SmallBlockChainStream_Construct(
-	       StorageImpl* parentStorage,	
-	       ULONG          propertyIndex);
-
-void SmallBlockChainStream_Destroy(
-	       SmallBlockChainStream* This);
-
-ULONG SmallBlockChainStream_GetHeadOfChain(
-	       SmallBlockChainStream* This);
-
-ULONG SmallBlockChainStream_GetNextBlockInChain(
-	       SmallBlockChainStream* This,
-	       ULONG                  blockIndex);
-
-void SmallBlockChainStream_SetNextBlockInChain(
-         SmallBlockChainStream* This,
-         ULONG                  blockIndex,
-         ULONG                  nextBlock);
-
-void SmallBlockChainStream_FreeBlock(
-         SmallBlockChainStream* This,
-         ULONG                  blockIndex);
-
-ULONG SmallBlockChainStream_GetNextFreeBlock(
-         SmallBlockChainStream* This);
-
-BOOL SmallBlockChainStream_ReadAt(
-	       SmallBlockChainStream* This,
-	       ULARGE_INTEGER offset,
-	       ULONG          size,
-	       void*          buffer,
-	       ULONG*         bytesRead);
-
-BOOL SmallBlockChainStream_WriteAt(
-	       SmallBlockChainStream* This,
-	       ULARGE_INTEGER offset,
-	       ULONG          size,
-	       const void*    buffer,
-	       ULONG*         bytesWritten);
-
-BOOL SmallBlockChainStream_SetSize(
-	       SmallBlockChainStream* This,
-	       ULARGE_INTEGER          newSize);
-
-ULARGE_INTEGER SmallBlockChainStream_GetSize(
-         SmallBlockChainStream* This);
-
-ULONG SmallBlockChainStream_GetCount(
-         SmallBlockChainStream* This);
-
-// Temp
-void OLECONVERT_CreateEmbeddedOleStream(LPSTORAGE pStorage);
-HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName);
-
-
-#endif /* __STORAGE32_H__ */
-
-
-
Index: trunk/src/ole32/storage32.c
===================================================================
--- trunk/src/ole32/storage32.c	(revision 5026)
+++ trunk/src/ole32/storage32.c	(revision 5026)
@@ -0,0 +1,7021 @@
+/*
+ * Compound Storage (32 bit version)
+ * Storage implementation
+ *
+ * This file contains the compound file implementation
+ * of the storage interface.
+ *
+ * Copyright 1999 Francis Beaudet
+ * Copyright 1999 Sylvain St-Germain
+ * Copyright 1999 Thuy Nguyen
+ */
+
+#ifdef __WIN32OS2__
+#define WINE_LARGE_INTEGER
+
+#include <odin.h>
+#include "ole32.h"
+#include "heapstring.h"
+
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "winbase.h" /* for lstrlenW() and the likes */
+#include "winnls.h"
+#include "wine/unicode.h"
+#include "debugtools.h"
+
+#include "storage32.h"
+#include "ole2.h"      /* For Write/ReadClassStm */
+
+#include "winreg.h"
+#include "wine/wingdi16.h"
+
+DEFAULT_DEBUG_CHANNEL(storage);
+
+#define FILE_BEGIN 0
+
+
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+#define OLESTREAM_ID 0x501
+#define OLESTREAM_MAX_STR_LEN 255
+
+static const char rootPropertyName[] = "Root Entry";
+
+
+/* OLESTREAM memory structure to use for Get and Put Routines */
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+typedef struct 
+{
+    DWORD dwOleID;
+    DWORD dwTypeID;
+    DWORD dwOleTypeNameLength;
+    CHAR  strOleTypeName[OLESTREAM_MAX_STR_LEN];
+    CHAR  *pstrOleObjFileName;
+    DWORD dwOleObjFileNameLength;
+    DWORD dwMetaFileWidth;
+    DWORD dwMetaFileHeight;
+    CHAR  strUnknown[8]; /* don't know what is this 8 byts information in OLE stream. */
+    DWORD dwDataLength;
+    BYTE *pData;
+}OLECONVERT_OLESTREAM_DATA;
+
+/* CompObj Stream structure */
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+typedef struct
+{
+    BYTE byUnknown1[12];
+    CLSID clsid;
+    DWORD dwCLSIDNameLength;
+    CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
+    DWORD dwOleTypeNameLength;
+    CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
+    DWORD dwProgIDNameLength;
+    CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
+    BYTE byUnknown2[16];
+}OLECONVERT_ISTORAGE_COMPOBJ;
+
+
+/* Ole Presention Stream structure */
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+typedef struct
+{
+    BYTE byUnknown1[28];
+    DWORD dwExtentX;
+    DWORD dwExtentY;
+    DWORD dwSize;  
+    BYTE *pData;
+}OLECONVERT_ISTORAGE_OLEPRES;
+
+
+
+/***********************************************************************
+ * Forward declaration of internal functions used by the method DestroyElement
+ */
+static HRESULT deleteStorageProperty(
+  StorageImpl *parentStorage,
+  ULONG        foundPropertyIndexToDelete,
+  StgProperty  propertyToDelete);
+
+static HRESULT deleteStreamProperty(
+  StorageImpl *parentStorage,
+  ULONG         foundPropertyIndexToDelete,
+  StgProperty   propertyToDelete);
+
+static HRESULT findPlaceholder(
+  StorageImpl *storage,
+  ULONG         propertyIndexToStore,
+  ULONG         storagePropertyIndex,
+  INT         typeOfRelation);
+
+static HRESULT adjustPropertyChain( 
+  StorageImpl *This,
+  StgProperty   propertyToDelete,
+  StgProperty   parentProperty,
+  ULONG         parentPropertyId,
+  INT         typeOfRelation);
+
+/***********************************************************************
+ * Declaration of the functions used to manipulate StgProperty
+ */
+
+static ULONG getFreeProperty(
+  StorageImpl *storage);
+
+static void updatePropertyChain(
+  StorageImpl *storage,
+  ULONG       newPropertyIndex,
+  StgProperty newProperty);
+
+static LONG propertyNameCmp(
+  OLECHAR *newProperty,
+  OLECHAR *currentProperty);
+
+
+/***********************************************************************
+ * Declaration of miscellaneous functions...
+ */
+static HRESULT validateSTGM(DWORD stgmValue); 
+
+static DWORD GetShareModeFromSTGM(DWORD stgm);
+static DWORD GetAccessModeFromSTGM(DWORD stgm);
+static DWORD GetCreationModeFromSTGM(DWORD stgm);
+
+/*
+ * Virtual function table for the IStorage32Impl class.
+ */
+static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    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,
+    StorageBaseImpl_Stat
+};
+
+/*
+ * Virtual function table for the Storage32InternalImpl class.
+ */
+static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
+  {
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    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.
+ */
+static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    IEnumSTATSTGImpl_QueryInterface,
+    IEnumSTATSTGImpl_AddRef,
+    IEnumSTATSTGImpl_Release,
+    IEnumSTATSTGImpl_Next,
+    IEnumSTATSTGImpl_Skip,
+    IEnumSTATSTGImpl_Reset,
+    IEnumSTATSTGImpl_Clone
+};
+
+
+
+
+
+/************************************************************************
+** Storage32BaseImpl implementatiion
+*/
+
+/************************************************************************
+ * Storage32BaseImpl_QueryInterface (IUnknown)
+ *
+ * This method implements the common QueryInterface for all IStorage32
+ * implementations contained in this file.
+ * 
+ * See Windows documentation for more details on IUnknown methods.
+ */
+HRESULT WINAPI StorageBaseImpl_QueryInterface(
+  IStorage*        iface,
+  REFIID             riid,
+  void**             ppvObject)
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppvObject==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+  
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = (IStorage*)This;
+  }
+  else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0) 
+  {
+    *ppvObject = (IStorage*)This;
+  }
+  
+  /*
+   * 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
+   */
+  StorageBaseImpl_AddRef(iface);
+
+  return S_OK;
+}
+        
+/************************************************************************
+ * Storage32BaseImpl_AddRef (IUnknown)
+ *
+ * This method implements the common AddRef for all IStorage32
+ * implementations contained in this file.
+ * 
+ * See Windows documentation for more details on IUnknown methods.
+ */
+ULONG WINAPI StorageBaseImpl_AddRef( 
+            IStorage* iface)
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  This->ref++;
+
+  return This->ref;
+}
+        
+/************************************************************************
+ * Storage32BaseImpl_Release (IUnknown)
+ *
+ * This method implements the common Release for all IStorage32
+ * implementations contained in this file.
+ * 
+ * See Windows documentation for more details on IUnknown methods.
+ */
+ULONG WINAPI StorageBaseImpl_Release( 
+      IStorage* iface)
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  /*
+   * Decrease the reference count on this object.
+   */
+  This->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (This->ref==0)
+  {
+    /*
+     * Since we are using a system of base-classes, we want to call the 
+     * destructor of the appropriate derived class. To do this, we are 
+     * using virtual functions to implement the destructor.
+     */
+    This->v_destructor(This);
+
+    return 0;
+  }
+  
+  return This->ref;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_OpenStream (IStorage)
+ *
+ * This method will open the specified stream object from the current storage.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_OpenStream( 
+  IStorage*        iface,
+  const OLECHAR*   pwcsName,  /* [string][in] */
+  void*            reserved1, /* [unique][in] */
+  DWORD            grfMode,   /* [in]  */        
+  DWORD            reserved2, /* [in]  */        
+  IStream**        ppstm)     /* [out] */       
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  IEnumSTATSTGImpl* propertyEnumeration;
+  StgStreamImpl*    newStream;
+  StgProperty       currentProperty;
+  ULONG             foundPropertyIndex;
+
+  TRACE("(%p, %s, %p, %lx, %ld, %p)\n", 
+	iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (pwcsName==NULL) || (ppstm==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the out parameter
+   */
+  *ppstm = 0;
+  
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * As documented.
+   */
+  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
+        (grfMode & STGM_DELETEONRELEASE) ||
+        (grfMode & STGM_TRANSACTED) )
+    return STG_E_INVALIDFUNCTION;
+
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(
+    This->ancestorStorage, 
+    This->rootPropertySetIndex);
+  
+  /*
+   * Search the enumeration for the property with the given name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
+    propertyEnumeration,
+    pwcsName,
+    &currentProperty);
+  
+  /*
+   * Delete the property enumeration since we don't need it anymore
+   */
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+  
+  /*
+   * If it was found, construct the stream object and return a pointer to it.
+   */
+  if ( (foundPropertyIndex!=PROPERTY_NULL) && 
+       (currentProperty.propertyType==PROPTYPE_STREAM) )
+  {
+    newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);
+    
+    if (newStream!=0)
+    {
+      newStream->grfMode = grfMode;
+      *ppstm = (IStream*)newStream;
+
+      /*
+       * Since we are returning a pointer to the interface, we have to 
+       * nail down the reference.
+       */
+      StgStreamImpl_AddRef(*ppstm);
+      
+      return S_OK;
+    }
+    
+    return E_OUTOFMEMORY;
+  }
+  
+  return STG_E_FILENOTFOUND;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_OpenStorage (IStorage)
+ *
+ * This method will open a new storage object from the current storage.
+ * 
+ * See Windows documentation for more details on IStorage methods.
+ */        
+HRESULT WINAPI StorageBaseImpl_OpenStorage( 
+  IStorage*        iface,
+  const OLECHAR*   pwcsName,      /* [string][unique][in] */ 
+  IStorage*        pstgPriority,  /* [unique][in] */         
+  DWORD            grfMode,       /* [in] */                 
+  SNB              snbExclude,    /* [unique][in] */         
+  DWORD            reserved,      /* [in] */                 
+  IStorage**       ppstg)         /* [out] */                        
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  StorageInternalImpl* newStorage;
+  IEnumSTATSTGImpl*      propertyEnumeration;
+  StgProperty            currentProperty;
+  ULONG                  foundPropertyIndex;
+
+  TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n", 
+	iface, debugstr_w(pwcsName), pstgPriority, 
+	grfMode, snbExclude, reserved, ppstg);
+  
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * As documented.
+   */
+  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) || 
+        (grfMode & STGM_DELETEONRELEASE) ||
+        (grfMode & STGM_PRIORITY) )
+    return STG_E_INVALIDFUNCTION;
+
+  /*
+   * Initialize the out parameter
+   */
+  *ppstg = 0;
+  
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(
+                          This->ancestorStorage, 
+                          This->rootPropertySetIndex);
+  
+  /*
+   * Search the enumeration for the property with the given name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
+                         propertyEnumeration,
+                         pwcsName,
+                         &currentProperty);
+  
+  /*
+   * Delete the property enumeration since we don't need it anymore
+   */
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+  
+  /*
+   * If it was found, construct the stream object and return a pointer to it.
+   */
+  if ( (foundPropertyIndex!=PROPERTY_NULL) && 
+       (currentProperty.propertyType==PROPTYPE_STORAGE) )
+  {
+    /*
+     * Construct a new Storage object
+     */
+    newStorage = StorageInternalImpl_Construct(
+                   This->ancestorStorage,
+                   foundPropertyIndex);
+    
+    if (newStorage != 0)
+    {
+      *ppstg = (IStorage*)newStorage;
+
+      /*
+       * Since we are returning a pointer to the interface, 
+       * we have to nail down the reference.
+       */
+      StorageBaseImpl_AddRef(*ppstg);
+      
+      return S_OK;
+    }
+    
+    return STG_E_INSUFFICIENTMEMORY;
+  }
+  
+  return STG_E_FILENOTFOUND;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_EnumElements (IStorage)
+ *
+ * This method will create an enumerator object that can be used to 
+ * retrieve informatino about all the properties in the storage object.
+ * 
+ * See Windows documentation for more details on IStorage methods.
+ */        
+HRESULT WINAPI StorageBaseImpl_EnumElements( 
+  IStorage*       iface,
+  DWORD           reserved1, /* [in] */                  
+  void*           reserved2, /* [size_is][unique][in] */ 
+  DWORD           reserved3, /* [in] */                  
+  IEnumSTATSTG**  ppenum)    /* [out] */                 
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  IEnumSTATSTGImpl* newEnum;
+
+  TRACE("(%p, %ld, %p, %ld, %p)\n", 
+	iface, reserved1, reserved2, reserved3, ppenum);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppenum==0))
+    return E_INVALIDARG;
+  
+  /*
+   * Construct the enumerator.
+   */
+  newEnum = IEnumSTATSTGImpl_Construct(
+              This->ancestorStorage,
+              This->rootPropertySetIndex);
+
+  if (newEnum!=0)
+  {
+    *ppenum = (IEnumSTATSTG*)newEnum;
+
+    /*
+     * Don't forget to nail down a reference to the new object before
+     * returning it.
+     */
+    IEnumSTATSTGImpl_AddRef(*ppenum);
+    
+    return S_OK;
+  }
+
+  return E_OUTOFMEMORY;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_Stat (IStorage)
+ *
+ * This method will retrieve information about this storage object.
+ * 
+ * See Windows documentation for more details on IStorage methods.
+ */        
+HRESULT WINAPI StorageBaseImpl_Stat( 
+  IStorage*        iface,
+  STATSTG*         pstatstg,     /* [out] */ 
+  DWORD            grfStatFlag)  /* [in] */  
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  StgProperty    curProperty;
+  BOOL         readSuccessful;
+
+  TRACE("(%p, %p, %lx)\n", 
+	iface, pstatstg, grfStatFlag);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (pstatstg==0))
+    return E_INVALIDARG;
+
+  /*
+   * Read the information from the property.
+   */
+  readSuccessful = StorageImpl_ReadProperty(
+                    This->ancestorStorage,
+                    This->rootPropertySetIndex,
+                    &curProperty);
+
+  if (readSuccessful)
+  {
+    StorageUtl_CopyPropertyToSTATSTG(
+      pstatstg, 
+      &curProperty, 
+      grfStatFlag);
+    
+    return S_OK;
+  }
+  
+  return E_FAIL;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_RenameElement (IStorage)
+ *
+ * This method will rename the specified element. 
+ *
+ * See Windows documentation for more details on IStorage methods.
+ * 
+ * Implementation notes: The method used to rename consists of creating a clone 
+ *    of the deleted StgProperty object setting it with the new name and to 
+ *    perform a DestroyElement of the old StgProperty.
+ */
+HRESULT WINAPI StorageBaseImpl_RenameElement(
+            IStorage*        iface,
+            const OLECHAR*   pwcsOldName,  /* [in] */
+            const OLECHAR*   pwcsNewName)  /* [in] */
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  IEnumSTATSTGImpl* propertyEnumeration;
+  StgProperty       currentProperty;
+  ULONG             foundPropertyIndex;
+
+  TRACE("(%p, %s, %s)\n", 
+	iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
+
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
+                                                   This->rootPropertySetIndex);
+
+  /*
+   * Search the enumeration for the new property name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsNewName,
+                                                     &currentProperty);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    /*
+     * There is already a property with the new name
+     */
+    IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+    return STG_E_FILEALREADYEXISTS;
+  }
+
+  IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
+
+  /*
+   * Search the enumeration for the old property name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsOldName,
+                                                     &currentProperty);
+
+  /*
+   * Delete the property enumeration since we don't need it anymore
+   */
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    StgProperty renamedProperty;
+    ULONG       renamedPropertyIndex;
+
+    /*
+     * Setup a new property for the renamed property
+     */
+    renamedProperty.sizeOfNameString = 
+      ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
+  
+    if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+      return STG_E_INVALIDNAME;
+  
+    strcpyW(renamedProperty.name, pwcsNewName);
+ 
+    renamedProperty.propertyType  = currentProperty.propertyType;
+    renamedProperty.startingBlock = currentProperty.startingBlock;
+    renamedProperty.size.s.LowPart  = currentProperty.size.s.LowPart;
+    renamedProperty.size.s.HighPart = currentProperty.size.s.HighPart;
+  
+    renamedProperty.previousProperty = PROPERTY_NULL;
+    renamedProperty.nextProperty     = PROPERTY_NULL;
+  
+    /*
+     * Bring the dirProperty link in case it is a storage and in which
+     * case the renamed storage elements don't require to be reorganized.
+     */
+    renamedProperty.dirProperty = currentProperty.dirProperty;
+  
+    /* call CoFileTime to get the current time 
+    renamedProperty.timeStampS1
+    renamedProperty.timeStampD1
+    renamedProperty.timeStampS2
+    renamedProperty.timeStampD2
+    renamedProperty.propertyUniqueID 
+    */
+  
+    /* 
+     * Obtain a free property in the property chain
+     */
+    renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
+  
+    /*
+     * Save the new property into the new property spot
+     */  
+    StorageImpl_WriteProperty(
+      This->ancestorStorage,
+      renamedPropertyIndex, 
+      &renamedProperty);
+  
+    /* 
+     * Find a spot in the property chain for our newly created property.
+     */
+    updatePropertyChain(
+      (StorageImpl*)This,
+      renamedPropertyIndex, 
+      renamedProperty);
+
+    /*
+     * At this point the renamed property has been inserted in the tree, 
+     * now, before to Destroy the old property we must zeroed it's dirProperty 
+     * otherwise the DestroyProperty below will zap it all and we do not want 
+     * this to happen.
+     * Also, we fake that the old property is a storage so the DestroyProperty
+     * will not do a SetSize(0) on the stream data.
+     * 
+     * This means that we need to tweek the StgProperty if it is a stream or a
+     * non empty storage.
+     */
+    StorageImpl_ReadProperty(This->ancestorStorage,
+                             foundPropertyIndex,
+                             &currentProperty);
+
+    currentProperty.dirProperty  = PROPERTY_NULL;
+    currentProperty.propertyType = PROPTYPE_STORAGE;
+    StorageImpl_WriteProperty(
+      This->ancestorStorage,
+      foundPropertyIndex, 
+      &currentProperty);
+
+    /* 
+     * Invoke Destroy to get rid of the ole property and automatically redo 
+     * the linking of it's previous and next members... 
+     */ 
+    StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName); 
+
+  }
+  else
+  {
+    /*
+     * There is no property with the old name
+     */
+    return STG_E_FILENOTFOUND;
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_CreateStream (IStorage)
+ *
+ * This method will create a stream object within this storage 
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_CreateStream(
+            IStorage*        iface,
+            const OLECHAR*   pwcsName,  /* [string][in] */
+            DWORD            grfMode,   /* [in] */
+            DWORD            reserved1, /* [in] */
+            DWORD            reserved2, /* [in] */
+            IStream**        ppstm)     /* [out] */
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  IEnumSTATSTGImpl* propertyEnumeration;
+  StgStreamImpl*    newStream;
+  StgProperty       currentProperty, newStreamProperty;
+  ULONG             foundPropertyIndex, newPropertyIndex;
+
+  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", 
+	iface, debugstr_w(pwcsName), grfMode, 
+	reserved1, reserved2, ppstm);
+
+  /*
+   * Validate parameters
+   */
+  if (ppstm == 0)
+    return STG_E_INVALIDPOINTER;
+
+  if (pwcsName == 0)
+    return STG_E_INVALIDNAME;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * As documented.
+   */
+  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
+        (grfMode & STGM_DELETEONRELEASE) ||
+        (grfMode & STGM_TRANSACTED) )
+    return STG_E_INVALIDFUNCTION;
+
+  /*
+   * Initialize the out parameter
+   */
+  *ppstm = 0;
+
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
+                                                   This->rootPropertySetIndex);
+
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsName,
+                                                     &currentProperty);
+
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    /*
+     * An element with this name already exists 
+     */
+    if (grfMode & STGM_CREATE)
+    {
+      IStorage_DestroyElement(iface, pwcsName); 
+    }
+    else 
+      return STG_E_FILEALREADYEXISTS;
+  }
+
+  /* 
+   * memset the empty property 
+   */
+  memset(&newStreamProperty, 0, sizeof(StgProperty));
+
+  newStreamProperty.sizeOfNameString =
+      ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
+
+  if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+    return STG_E_INVALIDNAME;
+
+  strcpyW(newStreamProperty.name, pwcsName);
+
+  newStreamProperty.propertyType  = PROPTYPE_STREAM;
+  newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
+  newStreamProperty.size.s.LowPart  = 0;
+  newStreamProperty.size.s.HighPart = 0;
+
+  newStreamProperty.previousProperty = PROPERTY_NULL;
+  newStreamProperty.nextProperty     = PROPERTY_NULL;
+  newStreamProperty.dirProperty      = PROPERTY_NULL;
+
+  /* call CoFileTime to get the current time 
+  newStreamProperty.timeStampS1
+  newStreamProperty.timeStampD1
+  newStreamProperty.timeStampS2
+  newStreamProperty.timeStampD2
+  */
+
+  /*  newStreamProperty.propertyUniqueID */
+
+  /*
+   * Get a free property or create a new one 
+   */
+  newPropertyIndex = getFreeProperty(This->ancestorStorage);
+
+  /*
+   * Save the new property into the new property spot
+   */  
+  StorageImpl_WriteProperty(
+    This->ancestorStorage,
+    newPropertyIndex, 
+    &newStreamProperty);
+
+  /* 
+   * Find a spot in the property chain for our newly created property.
+   */
+  updatePropertyChain(
+    (StorageImpl*)This,
+    newPropertyIndex, 
+    newStreamProperty);
+
+  /* 
+   * Open the stream to return it.
+   */
+  newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);
+
+  if (newStream != 0)
+  {
+    *ppstm = (IStream*)newStream;
+
+    /*
+     * Since we are returning a pointer to the interface, we have to nail down
+     * the reference.
+     */
+    StgStreamImpl_AddRef(*ppstm);
+  }
+  else
+  {
+    return STG_E_INSUFFICIENTMEMORY;
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_SetClass (IStorage)
+ *
+ * This method will write the specified CLSID in the property of this 
+ * storage.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_SetClass(
+  IStorage*        iface,
+  REFCLSID         clsid) /* [in] */
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  HRESULT hRes = E_FAIL;
+  StgProperty curProperty;
+  BOOL success;
+
+  TRACE("(%p, %p)\n", iface, clsid);
+  
+  success = StorageImpl_ReadProperty(This->ancestorStorage,
+                                       This->rootPropertySetIndex,
+                                       &curProperty);
+  if (success)
+  {
+    curProperty.propertyUniqueID = *clsid;
+
+    success =  StorageImpl_WriteProperty(This->ancestorStorage,
+                                           This->rootPropertySetIndex,
+                                           &curProperty);
+    if (success)
+      hRes = S_OK;
+  }
+
+  return hRes;
+}
+
+/************************************************************************
+** Storage32Impl implementation
+*/
+        
+/************************************************************************
+ * Storage32Impl_CreateStorage (IStorage)
+ *
+ * This method will create the storage object within the provided storage.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageImpl_CreateStorage( 
+  IStorage*      iface,
+  const OLECHAR  *pwcsName, /* [string][in] */ 
+  DWORD            grfMode,   /* [in] */ 
+  DWORD            reserved1, /* [in] */ 
+  DWORD            reserved2, /* [in] */ 
+  IStorage       **ppstg)   /* [out] */ 
+{
+  StorageImpl* const This=(StorageImpl*)iface;
+
+  IEnumSTATSTGImpl *propertyEnumeration;
+  StgProperty      currentProperty;
+  StgProperty      newProperty;
+  ULONG            foundPropertyIndex;
+  ULONG            newPropertyIndex;
+  HRESULT          hr;
+
+  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", 
+	iface, debugstr_w(pwcsName), grfMode, 
+	reserved1, reserved2, ppstg);
+  
+  /*
+   * Validate parameters
+   */
+  if (ppstg == 0)
+    return STG_E_INVALIDPOINTER;
+
+  if (pwcsName == 0)
+    return STG_E_INVALIDNAME;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ) ||
+       (grfMode & STGM_DELETEONRELEASE) )
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * Initialize the out parameter
+   */
+  *ppstg = 0;
+
+  /*
+   * Create a property enumeration and search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
+                                                    This->rootPropertySetIndex);
+
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsName,
+                                                     &currentProperty);
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    /*
+     * An element with this name already exists 
+     */
+    if (grfMode & STGM_CREATE)
+      IStorage_DestroyElement(iface, pwcsName); 
+    else 
+      return STG_E_FILEALREADYEXISTS;
+  }
+
+  /* 
+   * memset the empty property 
+   */
+  memset(&newProperty, 0, sizeof(StgProperty));
+
+  newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
+
+  if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+    return STG_E_INVALIDNAME;
+
+  strcpyW(newProperty.name, pwcsName);
+
+  newProperty.propertyType  = PROPTYPE_STORAGE;
+  newProperty.startingBlock = BLOCK_END_OF_CHAIN;
+  newProperty.size.s.LowPart  = 0;
+  newProperty.size.s.HighPart = 0;
+
+  newProperty.previousProperty = PROPERTY_NULL;
+  newProperty.nextProperty     = PROPERTY_NULL;
+  newProperty.dirProperty      = PROPERTY_NULL;
+
+  /* call CoFileTime to get the current time 
+  newProperty.timeStampS1
+  newProperty.timeStampD1
+  newProperty.timeStampS2
+  newProperty.timeStampD2
+  */
+
+  /*  newStorageProperty.propertyUniqueID */
+
+  /* 
+   * Obtain a free property in the property chain
+   */
+  newPropertyIndex = getFreeProperty(This->ancestorStorage);
+
+  /*
+   * Save the new property into the new property spot
+   */  
+  StorageImpl_WriteProperty(
+    This->ancestorStorage,
+    newPropertyIndex, 
+    &newProperty);
+
+  /* 
+   * Find a spot in the property chain for our newly created property.
+   */
+  updatePropertyChain(
+    This,
+    newPropertyIndex, 
+    newProperty);
+
+  /* 
+   * Open it to get a pointer to return.
+   */
+  hr = IStorage_OpenStorage(
+         iface,
+         (OLECHAR*)pwcsName,
+         0,
+         grfMode,
+         0,
+         0,
+         ppstg);
+
+  if( (hr != S_OK) || (*ppstg == NULL))
+  {
+    return hr;
+  }
+
+  
+  return S_OK;
+}
+
+
+/***************************************************************************
+ *
+ * Internal Method
+ *
+ * Get a free property or create a new one.
+ */
+static ULONG getFreeProperty(
+  StorageImpl *storage)
+{
+  ULONG       currentPropertyIndex = 0;
+  ULONG       newPropertyIndex     = PROPERTY_NULL;
+  BOOL      readSuccessful        = TRUE;
+  StgProperty currentProperty;
+
+  do
+  {
+    /*
+     * Start by reading the root property
+     */
+    readSuccessful = StorageImpl_ReadProperty(storage->ancestorStorage,
+                                               currentPropertyIndex,
+                                               &currentProperty);
+    if (readSuccessful)
+    {
+      if (currentProperty.sizeOfNameString == 0)
+      {
+        /* 
+         * The property existis and is available, we found it.
+         */
+        newPropertyIndex = currentPropertyIndex;
+      }
+    }
+    else
+    {
+      /*
+       * We exhausted the property list, we will create more space below
+       */
+      newPropertyIndex = currentPropertyIndex;
+    }
+    currentPropertyIndex++;
+
+  } while (newPropertyIndex == PROPERTY_NULL);
+
+  /* 
+   * grow the property chain 
+   */
+  if (! readSuccessful)
+  {
+    StgProperty    emptyProperty;
+    ULARGE_INTEGER newSize;
+    ULONG          propertyIndex;
+    ULONG          lastProperty  = 0;
+    ULONG          blockCount    = 0;
+
+    /* 
+     * obtain the new count of property blocks 
+     */
+    blockCount = BlockChainStream_GetCount(
+                   storage->ancestorStorage->rootBlockChain)+1;
+
+    /* 
+     * initialize the size used by the property stream 
+     */
+    newSize.s.HighPart = 0;
+    newSize.s.LowPart  = storage->bigBlockSize * blockCount;
+
+    /* 
+     * add a property block to the property chain 
+     */
+    BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
+
+    /* 
+     * memset the empty property in order to initialize the unused newly 
+     * created property
+     */
+    memset(&emptyProperty, 0, sizeof(StgProperty));
+
+    /* 
+     * initialize them
+     */
+    lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount; 
+    
+    for(
+      propertyIndex = newPropertyIndex;
+      propertyIndex < lastProperty;
+      propertyIndex++)
+    {
+      StorageImpl_WriteProperty(
+        storage->ancestorStorage,
+        propertyIndex, 
+        &emptyProperty);
+    }
+  }
+
+  return newPropertyIndex;
+}
+
+/****************************************************************************
+ *
+ * Internal Method
+ *
+ * Case insensitive comparaison of StgProperty.name by first considering 
+ * their size.
+ *
+ * Returns <0 when newPrpoerty < currentProperty
+ *         >0 when newPrpoerty > currentProperty
+ *          0 when newPrpoerty == currentProperty
+ */
+static LONG propertyNameCmp(
+  OLECHAR *newProperty,
+  OLECHAR *currentProperty)
+{
+  LONG diff      = lstrlenW(newProperty) - lstrlenW(currentProperty);
+
+  if (diff == 0) 
+  {
+    /* 
+     * We compare the string themselves only when they are of the same lenght
+     */
+    diff = lstrcmpiW( newProperty, currentProperty);
+  }
+
+  return diff;  
+}
+
+/****************************************************************************
+ *
+ * Internal Method
+ *
+ * Properly link this new element in the property chain.
+ */
+static void updatePropertyChain(
+  StorageImpl *storage,
+  ULONG         newPropertyIndex,
+  StgProperty   newProperty) 
+{
+  StgProperty currentProperty;
+
+  /*
+   * Read the root property
+   */
+  StorageImpl_ReadProperty(storage->ancestorStorage,
+                             storage->rootPropertySetIndex,
+                             &currentProperty);
+
+  if (currentProperty.dirProperty != PROPERTY_NULL)
+  {
+    /* 
+     * The root storage contains some element, therefore, start the research
+     * for the appropriate location.
+     */
+    BOOL found = 0;
+    ULONG  current, next, previous, currentPropertyId;
+
+    /*
+     * Keep the StgProperty sequence number of the storage first property
+     */
+    currentPropertyId = currentProperty.dirProperty;
+
+    /*
+     * Read 
+     */
+    StorageImpl_ReadProperty(storage->ancestorStorage,
+                               currentProperty.dirProperty,
+                               &currentProperty);
+
+    previous = currentProperty.previousProperty;
+    next     = currentProperty.nextProperty;
+    current  = currentPropertyId;
+
+    while (found == 0)
+    {
+      LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
+  
+      if (diff < 0)
+      {
+        if (previous != PROPERTY_NULL)
+        {
+          StorageImpl_ReadProperty(storage->ancestorStorage,
+                                     previous,
+                                     &currentProperty);
+          current = previous;
+        }
+        else
+        {
+          currentProperty.previousProperty = newPropertyIndex;
+          StorageImpl_WriteProperty(storage->ancestorStorage,
+                                      current,
+                                      &currentProperty);
+          found = 1;
+        }
+      }
+      else if (diff > 0)
+      {
+        if (next != PROPERTY_NULL)
+        {
+          StorageImpl_ReadProperty(storage->ancestorStorage,
+                                     next,
+                                     &currentProperty);
+          current = next;
+        }
+        else
+        {
+          currentProperty.nextProperty = newPropertyIndex;
+          StorageImpl_WriteProperty(storage->ancestorStorage,
+                                      current,
+                                      &currentProperty);
+          found = 1;
+        }
+      }
+      else
+      {
+	/*
+	 * Trying to insert an item with the same name in the
+	 * subtree structure.
+	 */
+	assert(FALSE);
+      }
+
+      previous = currentProperty.previousProperty;
+      next     = currentProperty.nextProperty;
+    }
+  }
+  else
+  {
+    /* 
+     * The root storage is empty, link the new property to it's dir property
+     */
+    currentProperty.dirProperty = newPropertyIndex;
+    StorageImpl_WriteProperty(storage->ancestorStorage,
+                                storage->rootPropertySetIndex,
+                                &currentProperty);
+  }
+}
+
+      
+/*************************************************************************
+ * CopyTo (IStorage)
+ */
+HRESULT WINAPI StorageImpl_CopyTo( 
+  IStorage*   iface,
+  DWORD       ciidExclude,  /* [in] */ 
+  const IID*  rgiidExclude, /* [size_is][unique][in] */ 
+  SNB         snbExclude,   /* [unique][in] */ 
+  IStorage*   pstgDest)     /* [unique][in] */ 
+{
+  IEnumSTATSTG *elements     = 0;
+  STATSTG      curElement, strStat;
+  HRESULT      hr;
+  IStorage     *pstgTmp, *pstgChild;
+  IStream      *pstrTmp, *pstrChild;
+
+  if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
+    FIXME("Exclude option not implemented\n");
+
+  TRACE("(%p, %ld, %p, %p, %p)\n", 
+	iface, ciidExclude, rgiidExclude, 
+	snbExclude, pstgDest);
+
+  /*
+   * Perform a sanity check
+   */
+  if ( pstgDest == 0 )
+    return STG_E_INVALIDPOINTER;
+
+  /* 
+   * Enumerate the elements
+   */
+  hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
+
+  if ( hr != S_OK )
+    return hr;
+
+  /*
+   * set the class ID
+   */
+  IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
+  IStorage_SetClass( pstgDest, &curElement.clsid );
+  
+  do
+  {
+    /*
+     * Obtain the next element
+     */
+    hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
+
+    if ( hr == S_FALSE )
+    {
+      hr = S_OK;   /* done, every element has been copied */
+      break;
+    }
+
+    if (curElement.type == STGTY_STORAGE)
+    {
+      /*
+       * open child source storage
+       */
+      hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
+				 STGM_READ|STGM_SHARE_EXCLUSIVE,
+				 NULL, 0, &pstgChild );
+
+      if (hr != S_OK)
+        break;
+
+      /*
+       * Check if destination storage is not a child of the source
+       * storage, which will cause an infinite loop
+       */
+      if (pstgChild == pstgDest)
+      {
+	IEnumSTATSTG_Release(elements);
+
+	return STG_E_ACCESSDENIED;
+      }
+            
+      /*
+       * create a new storage in destination storage
+       */
+      hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
+                                   STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
+				   0, 0,
+                                   &pstgTmp );
+      /*
+       * if it already exist, don't create a new one use this one
+       */
+      if (hr == STG_E_FILEALREADYEXISTS)
+      {
+        hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
+                                   STGM_WRITE|STGM_SHARE_EXCLUSIVE,
+                                   NULL, 0, &pstgTmp );
+      }
+        
+      if (hr != S_OK)
+        break;
+
+        
+      /*
+       * do the copy recursively
+       */
+      hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
+                               snbExclude, pstgTmp );
+                                
+      IStorage_Release( pstgTmp );
+      IStorage_Release( pstgChild );
+    }
+    else if (curElement.type == STGTY_STREAM)
+    {
+      /*
+       * create a new stream in destination storage. If the stream already
+       * exist, it will be deleted and a new one will be created.
+       */
+      hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
+                                  STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
+                                  0, 0, &pstrTmp );
+
+      if (hr != S_OK)
+        break;
+
+      /*
+       * open child stream storage
+       */
+      hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
+				STGM_READ|STGM_SHARE_EXCLUSIVE,
+				0, &pstrChild );
+
+      if (hr != S_OK)
+        break;
+
+      /*
+       * Get the size of the source stream
+       */
+      IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
+
+      /*
+       * Set the size of the destination stream.
+       */
+      IStream_SetSize(pstrTmp, strStat.cbSize);
+      
+      /*
+       * do the copy
+       */
+      hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
+                           NULL, NULL );
+                                
+      IStream_Release( pstrTmp );
+      IStream_Release( pstrChild );
+    }
+    else
+    {
+      WARN("unknown element type: %ld\n", curElement.type);
+    }
+
+  } while (hr == S_OK);
+
+  /*
+   * Clean-up
+   */
+  IEnumSTATSTG_Release(elements);
+  
+  return hr;
+}
+        
+/*************************************************************************
+ * MoveElementTo (IStorage)
+ */
+HRESULT WINAPI StorageImpl_MoveElementTo( 
+  IStorage*     iface,
+  const OLECHAR *pwcsName,   /* [string][in] */ 
+  IStorage      *pstgDest,   /* [unique][in] */ 
+  const OLECHAR *pwcsNewName,/* [string][in] */ 
+  DWORD           grfFlags)    /* [in] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+        
+/*************************************************************************
+ * Commit (IStorage)
+ */
+HRESULT WINAPI StorageImpl_Commit( 
+  IStorage*   iface,
+  DWORD         grfCommitFlags)/* [in] */ 
+{
+  FIXME("(%ld): stub!\n", grfCommitFlags);
+  return S_OK;
+}
+        
+/*************************************************************************
+ * Revert (IStorage)
+ */
+HRESULT WINAPI StorageImpl_Revert( 
+  IStorage* iface)
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+/*************************************************************************
+ * DestroyElement (IStorage)
+ *
+ * Stategy: This implementation is build this way for simplicity not for speed. 
+ *          I always delete the top most element of the enumeration and adjust
+ *          the deleted element pointer all the time.  This takes longer to 
+ *          do but allow to reinvoke DestroyElement whenever we encounter a 
+ *          storage object.  The optimisation reside in the usage of another
+ *          enumeration stategy that would give all the leaves of a storage 
+ *          first. (postfix order)
+ */
+HRESULT WINAPI StorageImpl_DestroyElement( 
+  IStorage*     iface,
+  const OLECHAR *pwcsName)/* [string][in] */ 
+{
+  StorageImpl* const This=(StorageImpl*)iface;
+
+  IEnumSTATSTGImpl* propertyEnumeration;
+  HRESULT           hr = S_OK;
+  BOOL            res;
+  StgProperty       propertyToDelete;
+  StgProperty       parentProperty;
+  ULONG             foundPropertyIndexToDelete;
+  ULONG             typeOfRelation;
+  ULONG             parentPropertyId;
+
+  TRACE("(%p, %s)\n", 
+	iface, debugstr_w(pwcsName));
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (pwcsName==NULL) 
+    return STG_E_INVALIDPOINTER;
+  
+  /*
+   * Create a property enumeration to search the property with the given name
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(
+    This->ancestorStorage, 
+    This->rootPropertySetIndex);
+  
+  foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
+    propertyEnumeration,
+    pwcsName,
+    &propertyToDelete);
+
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if ( foundPropertyIndexToDelete == PROPERTY_NULL )  
+  {
+    return STG_E_FILENOTFOUND;
+  }
+
+  /* 
+   * Find the parent property of the property to delete (the one that 
+   * link to it).  If This->dirProperty == foundPropertyIndexToDelete, 
+   * the parent is This. Otherwise, the parent is one of it's sibling...
+   */
+
+  /* 
+   * First, read This's StgProperty..
+   */
+  res = StorageImpl_ReadProperty( 
+          This->ancestorStorage,
+          This->rootPropertySetIndex,
+          &parentProperty);
+
+  assert(res==TRUE);
+
+  /* 
+   * Second, check to see if by any chance the actual storage (This) is not
+   * the parent of the property to delete... We never know...
+   */
+  if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
+  {
+    /* 
+     * Set data as it would have been done in the else part...
+     */
+    typeOfRelation   = PROPERTY_RELATION_DIR;
+    parentPropertyId = This->rootPropertySetIndex;
+  }
+  else 
+  { 
+    /*
+     * Create a property enumeration to search the parent properties, and 
+     * delete it once done.
+     */
+    IEnumSTATSTGImpl* propertyEnumeration2;
+
+    propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
+      This->ancestorStorage, 
+      This->rootPropertySetIndex);
+  
+    typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
+      propertyEnumeration2,
+      foundPropertyIndexToDelete,
+      &parentProperty,
+      &parentPropertyId);
+
+    IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
+  }
+
+  if ( propertyToDelete.propertyType == PROPTYPE_STORAGE ) 
+  {
+    hr = deleteStorageProperty(
+           This, 
+           foundPropertyIndexToDelete,
+           propertyToDelete);
+  } 
+  else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
+  {
+    hr = deleteStreamProperty(
+           This, 
+           foundPropertyIndexToDelete,
+           propertyToDelete);
+  }
+
+  if (hr!=S_OK) 
+    return hr;
+
+  /*
+   * Adjust the property chain
+   */
+  hr = adjustPropertyChain(
+        This,
+        propertyToDelete, 
+        parentProperty,
+        parentPropertyId,
+        typeOfRelation);
+
+  return hr;
+}
+
+
+/*********************************************************************
+ *
+ * Internal Method
+ *
+ * Perform the deletion of a complete storage node
+ *
+ */
+static HRESULT deleteStorageProperty(
+  StorageImpl *parentStorage,
+  ULONG        indexOfPropertyToDelete,
+  StgProperty  propertyToDelete)
+{
+  IEnumSTATSTG *elements     = 0;
+  IStorage   *childStorage = 0;
+  STATSTG      currentElement;
+  HRESULT      hr;
+  HRESULT      destroyHr = S_OK;
+
+  /*
+   * Open the storage and enumerate it
+   */
+  hr = StorageBaseImpl_OpenStorage(
+        (IStorage*)parentStorage,
+        propertyToDelete.name,
+        0,
+        STGM_SHARE_EXCLUSIVE,
+        0,
+        0,
+        &childStorage);
+
+  if (hr != S_OK)
+  {
+    return hr;
+  }
+
+  /* 
+   * Enumerate the elements
+   */
+  IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
+
+  do
+  {
+    /*
+     * Obtain the next element
+     */
+    hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
+    if (hr==S_OK)
+    {
+      destroyHr = StorageImpl_DestroyElement(
+                    (IStorage*)childStorage, 
+                    (OLECHAR*)currentElement.pwcsName);
+
+      CoTaskMemFree(currentElement.pwcsName);
+    }
+
+    /*
+     * We need to Reset the enumeration every time because we delete elements
+     * and the enumeration could be invalid
+     */
+    IEnumSTATSTG_Reset(elements);
+
+  } while ((hr == S_OK) && (destroyHr == S_OK));
+
+  /*
+   * Invalidate the property by zeroing it's name member.
+   */
+  propertyToDelete.sizeOfNameString = 0;
+
+  StorageImpl_WriteProperty(parentStorage->ancestorStorage,
+                            indexOfPropertyToDelete,
+                            &propertyToDelete);
+
+  IStorage_Release(childStorage);
+  IEnumSTATSTG_Release(elements);
+    
+  return destroyHr;
+}
+
+/*********************************************************************
+ *
+ * Internal Method
+ *
+ * Perform the deletion of a stream node
+ *
+ */
+static HRESULT deleteStreamProperty(
+  StorageImpl *parentStorage,
+  ULONG         indexOfPropertyToDelete,
+  StgProperty   propertyToDelete)
+{
+  IStream      *pis;
+  HRESULT        hr;
+  ULARGE_INTEGER size;
+
+  size.s.HighPart = 0;
+  size.s.LowPart = 0;
+
+  hr = StorageBaseImpl_OpenStream(
+         (IStorage*)parentStorage,
+         (OLECHAR*)propertyToDelete.name,
+         NULL,
+         STGM_WRITE | STGM_SHARE_EXCLUSIVE,
+         0,
+         &pis);
+    
+  if (hr!=S_OK)
+  {
+    return(hr);
+  }
+
+  /* 
+   * Zap the stream 
+   */ 
+  hr = IStream_SetSize(pis, size); 
+
+  if(hr != S_OK)
+  {
+    return hr;
+  }
+
+  /*
+   * Release the stream object.
+   */
+  IStream_Release(pis);
+
+  /* 
+   * Invalidate the property by zeroing it's name member.
+   */
+  propertyToDelete.sizeOfNameString = 0;
+
+  /* 
+   * Here we should re-read the property so we get the updated pointer
+   * but since we are here to zap it, I don't do it...
+   */
+  StorageImpl_WriteProperty(
+    parentStorage->ancestorStorage, 
+    indexOfPropertyToDelete,
+    &propertyToDelete);
+
+  return S_OK;
+}
+
+/*********************************************************************
+ *
+ * Internal Method
+ *
+ * Finds a placeholder for the StgProperty within the Storage
+ *
+ */
+static HRESULT findPlaceholder(
+  StorageImpl *storage,
+  ULONG         propertyIndexToStore,
+  ULONG         storePropertyIndex,
+  INT         typeOfRelation)
+{
+  StgProperty storeProperty;
+  HRESULT     hr = S_OK;
+  BOOL      res = TRUE;
+
+  /*
+   * Read the storage property
+   */
+  res = StorageImpl_ReadProperty(
+          storage->ancestorStorage,
+          storePropertyIndex, 
+          &storeProperty);
+
+  if(! res)
+  {
+    return E_FAIL;
+  }
+
+  if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
+  {
+    if (storeProperty.previousProperty != PROPERTY_NULL)
+    {
+      return findPlaceholder(
+               storage,
+               propertyIndexToStore, 
+               storeProperty.previousProperty,
+               typeOfRelation);
+    }
+    else
+    {
+      storeProperty.previousProperty = propertyIndexToStore;
+    }
+  }
+  else if (typeOfRelation == PROPERTY_RELATION_NEXT)
+  {
+    if (storeProperty.nextProperty != PROPERTY_NULL)
+    {
+      return findPlaceholder(
+               storage,
+               propertyIndexToStore, 
+               storeProperty.nextProperty,
+               typeOfRelation);
+    }
+    else
+    {
+      storeProperty.nextProperty = propertyIndexToStore;
+    }
+  } 
+  else if (typeOfRelation == PROPERTY_RELATION_DIR)
+  {
+    if (storeProperty.dirProperty != PROPERTY_NULL)
+    {
+      return findPlaceholder(
+               storage,
+               propertyIndexToStore, 
+               storeProperty.dirProperty,
+               typeOfRelation);
+    }
+    else
+    {
+      storeProperty.dirProperty = propertyIndexToStore;
+    }
+  }
+
+  hr = StorageImpl_WriteProperty(
+         storage->ancestorStorage,
+         storePropertyIndex, 
+         &storeProperty);
+
+  if(! hr)
+  {
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+/*************************************************************************
+ *
+ * Internal Method
+ *
+ * This method takes the previous and the next property link of a property 
+ * to be deleted and find them a place in the Storage.
+ */
+static HRESULT adjustPropertyChain( 
+  StorageImpl *This,
+  StgProperty   propertyToDelete,
+  StgProperty   parentProperty,
+  ULONG         parentPropertyId,
+  INT         typeOfRelation)
+{
+  ULONG   newLinkProperty        = PROPERTY_NULL;
+  BOOL  needToFindAPlaceholder = FALSE;
+  ULONG   storeNode              = PROPERTY_NULL;
+  ULONG   toStoreNode            = PROPERTY_NULL;
+  INT   relationType           = 0;
+  HRESULT hr                     = S_OK;
+  BOOL  res                    = TRUE;
+  
+  if (typeOfRelation == PROPERTY_RELATION_PREVIOUS) 
+  {
+    if (propertyToDelete.previousProperty != PROPERTY_NULL)  
+    {
+      /* 
+       * Set the parent previous to the property to delete previous
+       */
+      newLinkProperty = propertyToDelete.previousProperty;
+
+      if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+      {
+        /*
+         * We also need to find a storage for the other link, setup variables 
+         * to do this at the end...
+         */      
+        needToFindAPlaceholder = TRUE;
+        storeNode              = propertyToDelete.previousProperty;
+        toStoreNode            = propertyToDelete.nextProperty;
+        relationType           = PROPERTY_RELATION_NEXT;
+      }
+    } 
+    else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+    {
+      /* 
+       * Set the parent previous to the property to delete next
+       */
+      newLinkProperty = propertyToDelete.nextProperty;
+    }
+   
+    /* 
+     * Link it for real...
+     */ 
+    parentProperty.previousProperty = newLinkProperty;
+  
+  } 
+  else if (typeOfRelation == PROPERTY_RELATION_NEXT) 
+  {
+    if (propertyToDelete.previousProperty != PROPERTY_NULL)  
+    {
+      /* 
+       * Set the parent next to the property to delete next previous
+       */
+      newLinkProperty = propertyToDelete.previousProperty;
+      
+      if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+      {
+        /*
+         * We also need to find a storage for the other link, setup variables 
+         * to do this at the end...
+         */      
+        needToFindAPlaceholder = TRUE;
+        storeNode              = propertyToDelete.previousProperty;
+        toStoreNode            = propertyToDelete.nextProperty;
+        relationType           = PROPERTY_RELATION_NEXT;
+      }
+    } 
+    else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+    {
+      /* 
+       * Set the parent next to the property to delete next
+       */
+      newLinkProperty = propertyToDelete.nextProperty;
+    }
+
+    /* 
+     * Link it for real...
+     */ 
+    parentProperty.nextProperty = newLinkProperty;
+  } 
+  else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
+  {
+    if (propertyToDelete.previousProperty != PROPERTY_NULL) 
+    {
+      /* 
+       * Set the parent dir to the property to delete previous
+       */
+      newLinkProperty = propertyToDelete.previousProperty;
+
+      if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+      {
+        /*
+         * We also need to find a storage for the other link, setup variables 
+         * to do this at the end...
+         */      
+        needToFindAPlaceholder = TRUE;
+        storeNode              = propertyToDelete.previousProperty;
+        toStoreNode            = propertyToDelete.nextProperty;
+        relationType           = PROPERTY_RELATION_NEXT;
+      }
+    } 
+    else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+    {
+      /* 
+       * Set the parent dir to the property to delete next
+       */
+      newLinkProperty = propertyToDelete.nextProperty;
+    }
+
+    /* 
+     * Link it for real...
+     */ 
+    parentProperty.dirProperty = newLinkProperty;
+  }
+
+  /* 
+   * Write back the parent property    
+   */
+  res = StorageImpl_WriteProperty(
+          This->ancestorStorage, 
+          parentPropertyId,
+          &parentProperty);
+  if(! res)
+  {
+    return E_FAIL;
+  }
+
+  /*
+   * If a placeholder is required for the other link, then, find one and 
+   * get out of here...
+   */
+  if (needToFindAPlaceholder) 
+  {
+    hr = findPlaceholder(
+           This, 
+           toStoreNode, 
+           storeNode,
+           relationType);
+  }
+
+  return hr;
+}
+
+
+/******************************************************************************
+ * SetElementTimes (IStorage)
+ */
+HRESULT WINAPI StorageImpl_SetElementTimes( 
+  IStorage*     iface,
+  const OLECHAR *pwcsName,/* [string][in] */ 
+  const FILETIME  *pctime,  /* [in] */ 
+  const FILETIME  *patime,  /* [in] */ 
+  const FILETIME  *pmtime)  /* [in] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+/******************************************************************************
+ * SetStateBits (IStorage)
+ */
+HRESULT WINAPI StorageImpl_SetStateBits( 
+  IStorage*   iface,
+  DWORD         grfStateBits,/* [in] */ 
+  DWORD         grfMask)     /* [in] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+HRESULT StorageImpl_Construct(
+  StorageImpl* This,
+  HANDLE       hFile,
+  ILockBytes*  pLkbyt,
+  DWORD        openFlags,
+  BOOL         fileBased,
+  BOOL         fileCreate)
+{
+  HRESULT     hr = S_OK;
+  StgProperty currentProperty;
+  BOOL      readSuccessful;
+  ULONG       currentPropertyIndex;
+  
+  if ( FAILED( validateSTGM(openFlags) ))
+    return STG_E_INVALIDFLAG;
+
+  memset(This, 0, sizeof(StorageImpl));
+  
+  /*
+   * Initialize the virtual fgunction table.
+   */
+  ICOM_VTBL(This)    = &Storage32Impl_Vtbl;
+  This->v_destructor = &StorageImpl_Destroy;
+  
+  /*
+   * This is the top-level storage so initialize the ancester pointer
+   * to this.
+   */
+  This->ancestorStorage = This;
+  
+  /*
+   * Initialize the physical support of the storage.
+   */
+  This->hFile = hFile;
+  
+  /*
+   * Initialize the big block cache.
+   */
+  This->bigBlockSize   = DEF_BIG_BLOCK_SIZE;
+  This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
+  This->bigBlockFile   = BIGBLOCKFILE_Construct(hFile,
+                                                pLkbyt,
+                                                openFlags,
+                                                This->bigBlockSize,
+                                                fileBased);
+
+  if (This->bigBlockFile == 0)
+    return E_FAIL;
+ 
+  if (fileCreate)
+  {
+    ULARGE_INTEGER size;
+    BYTE* bigBlockBuffer;
+
+    /*
+     * Initialize all header variables:
+     * - The big block depot consists of one block and it is at block 0
+     * - The properties start at block 1
+     * - There is no small block depot
+     */
+    memset( This->bigBlockDepotStart,     
+            BLOCK_UNUSED, 
+            sizeof(This->bigBlockDepotStart));
+
+    This->bigBlockDepotCount    = 1;
+    This->bigBlockDepotStart[0] = 0;
+    This->rootStartBlock        = 1;
+    This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;
+    This->bigBlockSizeBits      = DEF_BIG_BLOCK_SIZE_BITS;
+    This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;
+    This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
+    This->extBigBlockDepotCount = 0;
+
+    StorageImpl_SaveFileHeader(This);
+
+    /*
+     * Add one block for the big block depot and one block for the properties
+     */
+    size.s.HighPart = 0;
+    size.s.LowPart  = This->bigBlockSize * 3;
+    BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
+
+    /*
+     * Initialize the big block depot
+     */
+    bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
+    memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
+    StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
+    StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
+    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+  }
+  else
+  {
+    /*
+     * Load the header for the file.
+     */
+    hr = StorageImpl_LoadFileHeader(This);
+
+    if (FAILED(hr))
+    {
+      BIGBLOCKFILE_Destructor(This->bigBlockFile);
+
+      return hr;
+    }
+  }
+
+  /*
+   * There is no block depot cached yet.
+   */
+  This->indexBlockDepotCached = 0xFFFFFFFF;
+
+  /*
+   * Start searching for free blocks with block 0.
+   */
+  This->prevFreeBlock = 0;
+  
+  /*
+   * Create the block chain abstractions.
+   */
+  This->rootBlockChain = 
+    BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
+
+  This->smallBlockDepotChain = BlockChainStream_Construct(
+                                 This, 
+                                 &This->smallBlockDepotStart, 
+                                 PROPERTY_NULL);
+
+  /*
+   * Write the root property 
+   */
+  if (fileCreate)
+  {
+    StgProperty rootProp;
+    /*
+     * Initialize the property chain
+     */
+    memset(&rootProp, 0, sizeof(rootProp));
+    MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name,
+                         sizeof(rootProp.name)/sizeof(WCHAR) );
+    rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR);
+    rootProp.propertyType     = PROPTYPE_ROOT;
+    rootProp.previousProperty = PROPERTY_NULL;
+    rootProp.nextProperty     = PROPERTY_NULL;
+    rootProp.dirProperty      = PROPERTY_NULL;
+    rootProp.startingBlock    = BLOCK_END_OF_CHAIN;
+    rootProp.size.s.HighPart    = 0;
+    rootProp.size.s.LowPart     = 0;
+
+    StorageImpl_WriteProperty(This, 0, &rootProp);
+  }
+
+  /*
+   * Find the ID of the root int he property sets.
+   */
+  currentPropertyIndex = 0;
+  
+  do
+  {
+    readSuccessful = StorageImpl_ReadProperty(
+                      This, 
+                      currentPropertyIndex, 
+                      &currentProperty);
+    
+    if (readSuccessful)
+    {
+      if ( (currentProperty.sizeOfNameString != 0 ) &&
+           (currentProperty.propertyType     == PROPTYPE_ROOT) )
+      {
+        This->rootPropertySetIndex = currentPropertyIndex;
+      }
+    }
+
+    currentPropertyIndex++;
+    
+  } while (readSuccessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
+  
+  if (!readSuccessful)
+  {
+    /* TODO CLEANUP */
+    return E_FAIL;
+  }
+
+  /*
+   * Create the block chain abstraction for the small block root chain.
+   */
+  This->smallBlockRootChain = BlockChainStream_Construct(
+                                This, 
+                                NULL, 
+                                This->rootPropertySetIndex);
+  
+  return hr;
+}
+
+void StorageImpl_Destroy(
+  StorageImpl* This)
+{
+  TRACE("(%p)\n", This);
+
+  BlockChainStream_Destroy(This->smallBlockRootChain);
+  BlockChainStream_Destroy(This->rootBlockChain);
+  BlockChainStream_Destroy(This->smallBlockDepotChain);
+
+  BIGBLOCKFILE_Destructor(This->bigBlockFile);
+  return;
+}
+
+/******************************************************************************
+ *      Storage32Impl_GetNextFreeBigBlock
+ *
+ * Returns the index of the next free big block.
+ * If the big block depot is filled, this method will enlarge it.
+ *
+ */
+ULONG StorageImpl_GetNextFreeBigBlock(
+  StorageImpl* This)
+{
+  ULONG depotBlockIndexPos;
+  void  *depotBuffer;
+  ULONG depotBlockOffset;
+  ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
+  ULONG nextBlockIndex    = BLOCK_SPECIAL;
+  int   depotIndex        = 0;
+  ULONG freeBlock         = BLOCK_UNUSED;
+
+  depotIndex = This->prevFreeBlock / blocksPerDepot;
+  depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
+
+  /*
+   * Scan the entire big block depot until we find a block marked free
+   */
+  while (nextBlockIndex != BLOCK_UNUSED)
+  {
+    if (depotIndex < COUNT_BBDEPOTINHEADER)
+    {
+      depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
+
+      /*
+       * Grow the primary depot.
+       */
+      if (depotBlockIndexPos == BLOCK_UNUSED)
+      {
+        depotBlockIndexPos = depotIndex*blocksPerDepot;
+
+        /*
+         * Add a block depot.
+         */
+        Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
+        This->bigBlockDepotCount++;
+        This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
+
+        /*
+         * Flag it as a block depot.
+         */
+        StorageImpl_SetNextBlockInChain(This,
+                                          depotBlockIndexPos,
+                                          BLOCK_SPECIAL);
+
+        /* Save new header information.
+         */
+        StorageImpl_SaveFileHeader(This);
+      }
+    }
+    else
+    {
+      depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
+
+      if (depotBlockIndexPos == BLOCK_UNUSED)
+      {
+        /*
+         * Grow the extended depot.
+         */
+        ULONG extIndex       = BLOCK_UNUSED;
+        ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;
+        ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
+
+        if (extBlockOffset == 0)
+        {
+          /* We need an extended block.
+           */
+          extIndex = Storage32Impl_AddExtBlockDepot(This);
+          This->extBigBlockDepotCount++;
+          depotBlockIndexPos = extIndex + 1;
+        }
+        else
+          depotBlockIndexPos = depotIndex * blocksPerDepot;
+
+        /*
+         * Add a block depot and mark it in the extended block.
+         */
+        Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
+        This->bigBlockDepotCount++;
+        Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
+
+        /* Flag the block depot.
+         */
+        StorageImpl_SetNextBlockInChain(This,
+                                          depotBlockIndexPos,
+                                          BLOCK_SPECIAL);
+
+        /* If necessary, flag the extended depot block.
+         */
+        if (extIndex != BLOCK_UNUSED)
+          StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
+
+        /* Save header information.
+         */
+        StorageImpl_SaveFileHeader(This);
+      }
+    }
+
+    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+
+    if (depotBuffer != 0)
+    {
+      while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
+              ( nextBlockIndex != BLOCK_UNUSED))
+      {
+        StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
+
+        if (nextBlockIndex == BLOCK_UNUSED)
+        {
+          freeBlock = (depotIndex * blocksPerDepot) +
+                      (depotBlockOffset/sizeof(ULONG));
+        }
+
+        depotBlockOffset += sizeof(ULONG);
+      }
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+
+    depotIndex++;
+    depotBlockOffset = 0;
+  }
+
+  This->prevFreeBlock = freeBlock;
+
+  return freeBlock;
+}
+
+/******************************************************************************
+ *      Storage32Impl_AddBlockDepot
+ *
+ * This will create a depot block, essentially it is a block initialized
+ * to BLOCK_UNUSEDs.
+ */
+void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
+{
+  BYTE* blockBuffer;
+
+  blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
+
+  /*
+   * Initialize blocks as free
+   */
+  memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
+
+  StorageImpl_ReleaseBigBlock(This, blockBuffer);
+}
+
+/******************************************************************************
+ *      Storage32Impl_GetExtDepotBlock
+ *
+ * Returns the index of the block that corresponds to the specified depot
+ * index. This method is only for depot indexes equal or greater than
+ * COUNT_BBDEPOTINHEADER.
+ */
+ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
+{
+  ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
+  ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
+  ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
+  ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
+  ULONG blockIndex             = BLOCK_UNUSED;
+  ULONG extBlockIndex          = This->extBigBlockDepotStart;
+
+  assert(depotIndex >= COUNT_BBDEPOTINHEADER);
+
+  if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
+    return BLOCK_UNUSED;
+
+  while (extBlockCount > 0)
+  {
+    extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
+    extBlockCount--;
+  }
+
+  if (extBlockIndex != BLOCK_UNUSED)
+  {
+    BYTE* depotBuffer;
+
+    depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
+
+    if (depotBuffer != 0)
+    {
+      StorageUtl_ReadDWord(depotBuffer,
+                           extBlockOffset * sizeof(ULONG),
+                           &blockIndex);
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+  }
+
+  return blockIndex;
+}
+
+/******************************************************************************
+ *      Storage32Impl_SetExtDepotBlock
+ *
+ * Associates the specified block index to the specified depot index.
+ * This method is only for depot indexes equal or greater than
+ * COUNT_BBDEPOTINHEADER.
+ */
+void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
+                                    ULONG depotIndex,
+                                    ULONG blockIndex)
+{
+  ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
+  ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
+  ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
+  ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
+  ULONG extBlockIndex          = This->extBigBlockDepotStart;
+
+  assert(depotIndex >= COUNT_BBDEPOTINHEADER);
+
+  while (extBlockCount > 0)
+  {
+    extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
+    extBlockCount--;
+  }
+
+  if (extBlockIndex != BLOCK_UNUSED)
+  {
+    BYTE* depotBuffer;
+
+    depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
+
+    if (depotBuffer != 0)
+    {
+      StorageUtl_WriteDWord(depotBuffer,
+                            extBlockOffset * sizeof(ULONG),
+                            blockIndex);
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+  }
+}
+
+/******************************************************************************
+ *      Storage32Impl_AddExtBlockDepot
+ *
+ * Creates an extended depot block.
+ */
+ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
+{
+  ULONG numExtBlocks           = This->extBigBlockDepotCount;
+  ULONG nextExtBlock           = This->extBigBlockDepotStart;
+  BYTE* depotBuffer            = NULL;
+  ULONG index                  = BLOCK_UNUSED;
+  ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
+  ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
+  ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
+
+  index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
+          blocksPerDepotBlock;
+
+  if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
+  {
+    /*
+     * The first extended block.
+     */
+    This->extBigBlockDepotStart = index;
+  }
+  else
+  {
+    int i;
+    /*
+     * Follow the chain to the last one.
+     */
+    for (i = 0; i < (numExtBlocks - 1); i++)
+    {
+      nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
+    }
+
+    /*
+     * Add the new extended block to the chain.
+     */
+    depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
+    StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
+    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  }
+
+  /*
+   * Initialize this block.
+   */
+  depotBuffer = StorageImpl_GetBigBlock(This, index);
+  memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
+  StorageImpl_ReleaseBigBlock(This, depotBuffer);
+
+  return index;
+}
+
+/******************************************************************************
+ *      Storage32Impl_FreeBigBlock
+ *
+ * This method will flag the specified block as free in the big block depot.
+ */
+void  StorageImpl_FreeBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
+
+  if (blockIndex < This->prevFreeBlock)
+    This->prevFreeBlock = blockIndex;
+}
+
+/************************************************************************
+ * Storage32Impl_GetNextBlockInChain
+ *
+ * This method will retrieve the block index of the next big block in
+ * in the chain.
+ *
+ * Params:  This       - Pointer to the Storage object.
+ *          blockIndex - Index of the block to retrieve the chain
+ *                       for.
+ *
+ * Returns: This method returns the index of the next block in the chain.
+ *          It will return the constants:
+ *              BLOCK_SPECIAL - If the block given was not part of a
+ *                              chain.
+ *              BLOCK_END_OF_CHAIN - If the block given was the last in
+ *                                   a chain.
+ *              BLOCK_UNUSED - If the block given was not past of a chain
+ *                             and is available.
+ *              BLOCK_EXTBBDEPOT - This block is part of the extended
+ *                                 big block depot.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+ULONG StorageImpl_GetNextBlockInChain(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
+  ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
+  ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
+  ULONG nextBlockIndex   = BLOCK_SPECIAL;
+  void* depotBuffer;
+  ULONG depotBlockIndexPos;
+
+  assert(depotBlockCount < This->bigBlockDepotCount);
+
+  /*
+   * Cache the currently accessed depot block.
+   */
+  if (depotBlockCount != This->indexBlockDepotCached)
+  {
+    This->indexBlockDepotCached = depotBlockCount;
+
+    if (depotBlockCount < COUNT_BBDEPOTINHEADER)
+    {
+      depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
+    }
+    else
+    {
+      /*
+       * We have to look in the extended depot.
+       */
+      depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
+    }
+
+    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+
+    if (depotBuffer!=0)
+    {
+      int index;
+
+      for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
+      {
+        StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &nextBlockIndex);
+        This->blockDepotCached[index] = nextBlockIndex;
+      }
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+  }
+
+  nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
+
+  return nextBlockIndex;
+}
+
+/******************************************************************************
+ *      Storage32Impl_GetNextExtendedBlock
+ *
+ * Given an extended block this method will return the next extended block.
+ *
+ * NOTES:
+ * The last ULONG of an extended block is the block index of the next
+ * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
+ * depot.
+ *
+ * Return values:
+ *    - The index of the next extended block
+ *    - BLOCK_UNUSED: there is no next extended block.
+ *    - Any other return values denotes failure.
+ */
+ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
+{
+  ULONG nextBlockIndex   = BLOCK_SPECIAL;
+  ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
+  void* depotBuffer;
+
+  depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
+
+  if (depotBuffer!=0)
+  {
+    StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
+
+    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  }
+
+  return nextBlockIndex;
+}
+
+/******************************************************************************
+ *      Storage32Impl_SetNextBlockInChain
+ *
+ * This method will write the index of the specified block's next block
+ * in the big block depot.
+ *
+ * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
+ *              do the following
+ *
+ * Storage32Impl_SetNextBlockInChain(This, 3, 1);
+ * Storage32Impl_SetNextBlockInChain(This, 1, 7);
+ * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
+ *
+ */
+void  StorageImpl_SetNextBlockInChain(
+          StorageImpl* This,
+          ULONG          blockIndex,
+          ULONG          nextBlock)
+{
+  ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
+  ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
+  ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
+  ULONG depotBlockIndexPos;
+  void* depotBuffer;
+
+  assert(depotBlockCount < This->bigBlockDepotCount);
+  assert(blockIndex != nextBlock);
+
+  if (depotBlockCount < COUNT_BBDEPOTINHEADER)
+  {
+    depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
+  }
+  else
+  {
+    /*
+     * We have to look in the extended depot.
+     */
+    depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
+  }
+
+  depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
+
+  if (depotBuffer!=0)
+  {
+    StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
+    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  }
+
+  /*
+   * Update the cached block depot, if necessary.
+   */
+  if (depotBlockCount == This->indexBlockDepotCached)
+  {
+    This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
+  }
+}
+
+/******************************************************************************
+ *      Storage32Impl_LoadFileHeader
+ *
+ * This method will read in the file header, i.e. big block index -1.
+ */
+HRESULT StorageImpl_LoadFileHeader(
+          StorageImpl* This)
+{
+  HRESULT hr = STG_E_FILENOTFOUND;
+  void*   headerBigBlock = NULL;
+  int     index;
+
+  /*
+   * Get a pointer to the big block of data containing the header.
+   */
+  headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
+
+  /*
+   * Extract the information from the header.
+   */
+  if (headerBigBlock!=0)
+  {
+    /*
+     * Check for the "magic number" signature and return an error if it is not
+     * found.
+     */
+    if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
+    {
+      StorageImpl_ReleaseBigBlock(This, headerBigBlock);
+      return STG_E_OLDFORMAT;
+    }
+
+    if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
+    {
+      StorageImpl_ReleaseBigBlock(This, headerBigBlock);
+      return STG_E_INVALIDHEADER;
+    }
+
+    StorageUtl_ReadWord(
+      headerBigBlock, 
+      OFFSET_BIGBLOCKSIZEBITS,   
+      &This->bigBlockSizeBits);
+
+    StorageUtl_ReadWord(
+      headerBigBlock, 
+      OFFSET_SMALLBLOCKSIZEBITS, 
+      &This->smallBlockSizeBits);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock, 
+      OFFSET_BBDEPOTCOUNT,      
+      &This->bigBlockDepotCount);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock, 
+      OFFSET_ROOTSTARTBLOCK,    
+      &This->rootStartBlock);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock, 
+      OFFSET_SBDEPOTSTART,      
+      &This->smallBlockDepotStart);
+
+    StorageUtl_ReadDWord( 
+      headerBigBlock, 
+      OFFSET_EXTBBDEPOTSTART,   
+      &This->extBigBlockDepotStart);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock, 
+      OFFSET_EXTBBDEPOTCOUNT,   
+      &This->extBigBlockDepotCount);
+    
+    for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
+    {
+      StorageUtl_ReadDWord(
+        headerBigBlock, 
+        OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
+        &(This->bigBlockDepotStart[index]));
+    }
+    
+    /*
+     * Make the bitwise arithmetic to get the size of the blocks in bytes.
+     */
+    if ((1 << 2) == 4)
+    {
+      This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
+      This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
+    }
+    else
+    {
+      This->bigBlockSize   = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
+      This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
+    }
+    
+    /*
+     * Right now, the code is making some assumptions about the size of the 
+     * blocks, just make sure they are what we're expecting.
+     */
+    assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) && 
+            (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
+    
+    /*
+     * Release the block.
+     */
+    StorageImpl_ReleaseBigBlock(This, headerBigBlock);
+
+    hr = S_OK;
+  }
+  
+  return hr;
+}
+
+/******************************************************************************
+ *      Storage32Impl_SaveFileHeader
+ *
+ * This method will save to the file the header, i.e. big block -1.
+ */
+void StorageImpl_SaveFileHeader(
+          StorageImpl* This)
+{
+  BYTE   headerBigBlock[BIG_BLOCK_SIZE];
+  int    index;
+  BOOL success;
+
+  /*
+   * Get a pointer to the big block of data containing the header.
+   */
+  success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
+  
+  /*
+   * If the block read failed, the file is probably new.
+   */
+  if (!success)
+  {
+    /*
+     * Initialize for all unknown fields.
+     */
+    memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
+    
+    /*
+     * Initialize the magic number.
+     */
+    memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
+    
+    /*
+     * And a bunch of things we don't know what they mean
+     */
+    StorageUtl_WriteWord(headerBigBlock,  0x18, 0x3b);
+    StorageUtl_WriteWord(headerBigBlock,  0x1a, 0x3);
+    StorageUtl_WriteWord(headerBigBlock,  0x1c, (WORD)-2);
+    StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
+    StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
+  }
+  
+  /*
+   * Write the information to the header.
+   */
+  if (headerBigBlock!=0)
+  {
+    StorageUtl_WriteWord(
+      headerBigBlock, 
+      OFFSET_BIGBLOCKSIZEBITS,   
+      This->bigBlockSizeBits);
+
+    StorageUtl_WriteWord(
+      headerBigBlock, 
+      OFFSET_SMALLBLOCKSIZEBITS, 
+      This->smallBlockSizeBits);
+
+    StorageUtl_WriteDWord(
+      headerBigBlock, 
+      OFFSET_BBDEPOTCOUNT,      
+      This->bigBlockDepotCount);
+
+    StorageUtl_WriteDWord(
+      headerBigBlock, 
+      OFFSET_ROOTSTARTBLOCK,    
+      This->rootStartBlock);
+
+    StorageUtl_WriteDWord(
+      headerBigBlock, 
+      OFFSET_SBDEPOTSTART,      
+      This->smallBlockDepotStart);
+
+    StorageUtl_WriteDWord(
+      headerBigBlock, 
+      OFFSET_EXTBBDEPOTSTART,   
+      This->extBigBlockDepotStart);
+
+    StorageUtl_WriteDWord(
+      headerBigBlock, 
+      OFFSET_EXTBBDEPOTCOUNT,   
+      This->extBigBlockDepotCount);
+
+    for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
+    {
+      StorageUtl_WriteDWord(
+        headerBigBlock, 
+        OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
+        (This->bigBlockDepotStart[index]));
+    }
+  }
+  
+  /*
+   * Write the big block back to the file.
+   */
+  StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
+}
+
+/******************************************************************************
+ *      Storage32Impl_ReadProperty
+ *
+ * This method will read the specified property from the property chain.
+ */
+BOOL StorageImpl_ReadProperty(
+  StorageImpl* This,
+  ULONG          index,
+  StgProperty*   buffer)
+{
+  BYTE           currentProperty[PROPSET_BLOCK_SIZE];
+  ULARGE_INTEGER offsetInPropSet;
+  BOOL         readSuccessful;
+  ULONG          bytesRead;
+
+  offsetInPropSet.s.HighPart = 0;
+  offsetInPropSet.s.LowPart  = index * PROPSET_BLOCK_SIZE;
+  
+  readSuccessful = BlockChainStream_ReadAt(
+                    This->rootBlockChain,
+                    offsetInPropSet,
+                    PROPSET_BLOCK_SIZE,
+                    currentProperty,
+                    &bytesRead);
+  
+  if (readSuccessful)
+  {
+    memset(buffer->name, 0, sizeof(buffer->name));
+    memcpy(
+      buffer->name, 
+      currentProperty+OFFSET_PS_NAME, 
+      PROPERTY_NAME_BUFFER_LEN );
+
+    memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
+    
+    StorageUtl_ReadWord(
+      currentProperty,  
+      OFFSET_PS_NAMELENGTH,  
+      &buffer->sizeOfNameString);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_PREVIOUSPROP, 
+      &buffer->previousProperty);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_NEXTPROP,     
+      &buffer->nextProperty);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_DIRPROP,      
+      &buffer->dirProperty);
+
+    StorageUtl_ReadGUID(
+      currentProperty,  
+      OFFSET_PS_GUID,        
+      &buffer->propertyUniqueID);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_TSS1,         
+      &buffer->timeStampS1);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_TSD1,         
+      &buffer->timeStampD1);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_TSS2,         
+      &buffer->timeStampS2);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_TSD2,         
+      &buffer->timeStampD2);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_STARTBLOCK,   
+      &buffer->startingBlock);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_SIZE,         
+      &buffer->size.s.LowPart);
+
+    buffer->size.s.HighPart = 0;
+  }
+
+  return readSuccessful;
+}
+
+/*********************************************************************
+ * Write the specified property into the property chain
+ */
+BOOL StorageImpl_WriteProperty(
+  StorageImpl* This,
+  ULONG          index,
+  StgProperty*   buffer)
+{
+  BYTE           currentProperty[PROPSET_BLOCK_SIZE];
+  ULARGE_INTEGER offsetInPropSet;
+  BOOL         writeSuccessful;
+  ULONG          bytesWritten;
+
+  offsetInPropSet.s.HighPart = 0;
+  offsetInPropSet.s.LowPart  = index * PROPSET_BLOCK_SIZE;
+
+  memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
+
+  memcpy(
+    currentProperty + OFFSET_PS_NAME, 
+    buffer->name, 
+    PROPERTY_NAME_BUFFER_LEN );
+
+  memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
+
+  StorageUtl_WriteWord(
+    currentProperty,  
+      OFFSET_PS_NAMELENGTH,   
+      buffer->sizeOfNameString);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_PREVIOUSPROP, 
+      buffer->previousProperty);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_NEXTPROP,     
+      buffer->nextProperty);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_DIRPROP,      
+      buffer->dirProperty);
+
+  StorageUtl_WriteGUID(
+    currentProperty,  
+      OFFSET_PS_GUID,        
+      &buffer->propertyUniqueID);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_TSS1,         
+      buffer->timeStampS1);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_TSD1,         
+      buffer->timeStampD1);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_TSS2,         
+      buffer->timeStampS2);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_TSD2,         
+      buffer->timeStampD2);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_STARTBLOCK,   
+      buffer->startingBlock);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_SIZE,         
+      buffer->size.s.LowPart);
+
+  writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain,
+                                            offsetInPropSet,
+                                            PROPSET_BLOCK_SIZE,
+                                            currentProperty,
+                                            &bytesWritten);
+  return writeSuccessful;
+}
+
+BOOL StorageImpl_ReadBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex,
+  void*          buffer)
+{
+  void* bigBlockBuffer;
+
+  bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
+
+  if (bigBlockBuffer!=0)
+  {
+    memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
+
+    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+BOOL StorageImpl_WriteBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex,
+  void*          buffer)
+{
+  void* bigBlockBuffer;
+
+  bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
+
+  if (bigBlockBuffer!=0)
+  {
+    memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
+
+    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+    
+    return TRUE;
+  }
+  
+  return FALSE;
+}
+
+void* StorageImpl_GetROBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
+}
+
+void* StorageImpl_GetBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
+}
+
+void StorageImpl_ReleaseBigBlock(
+  StorageImpl* This,
+  void*          pBigBlock)
+{
+  BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
+}
+
+/******************************************************************************
+ *              Storage32Impl_SmallBlocksToBigBlocks
+ *
+ * This method will convert a small block chain to a big block chain.
+ * The small block chain will be destroyed.
+ */
+BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
+                      StorageImpl* This,
+                      SmallBlockChainStream** ppsbChain)
+{
+  ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
+  ULARGE_INTEGER size, offset;
+  ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
+  ULONG propertyIndex;
+  BOOL successRead, successWrite;
+  StgProperty chainProperty;
+  BYTE *buffer;
+  BlockChainStream *bbTempChain = NULL;
+  BlockChainStream *bigBlockChain = NULL;
+
+  /*
+   * Create a temporary big block chain that doesn't have
+   * an associated property. This temporary chain will be
+   * used to copy data from small blocks to big blocks.
+   */
+  bbTempChain = BlockChainStream_Construct(This,
+                                           &bbHeadOfChain,
+                                           PROPERTY_NULL);
+
+  /*
+   * Grow the big block chain.
+   */
+  size = SmallBlockChainStream_GetSize(*ppsbChain);
+  BlockChainStream_SetSize(bbTempChain, size);
+
+  /*
+   * Copy the contents of the small block chain to the big block chain
+   * by small block size increments.
+   */
+  offset.s.LowPart = 0;
+  offset.s.HighPart = 0;
+  cbTotalRead = 0;
+  cbTotalWritten = 0;
+
+  buffer = (BYTE *) HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
+  do
+  {
+    successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
+                                               offset,
+                                               DEF_SMALL_BLOCK_SIZE,
+                                               buffer,
+                                               &cbRead);
+    cbTotalRead += cbRead;
+
+    successWrite = BlockChainStream_WriteAt(bbTempChain,
+                                            offset,
+                                            cbRead,
+                                            buffer,
+                                            &cbWritten);
+    cbTotalWritten += cbWritten;
+
+    offset.s.LowPart += This->smallBlockSize;
+
+  } while (successRead && successWrite);
+  HeapFree(GetProcessHeap(),0,buffer);
+
+  assert(cbTotalRead == cbTotalWritten);
+
+  /*
+   * Destroy the small block chain.
+   */
+  propertyIndex = (*ppsbChain)->ownerPropertyIndex;
+  size.s.HighPart = 0;
+  size.s.LowPart  = 0;
+  SmallBlockChainStream_SetSize(*ppsbChain, size);
+  SmallBlockChainStream_Destroy(*ppsbChain);
+  *ppsbChain = 0;
+
+  /*
+   * Change the property information. This chain is now a big block chain
+   * and it doesn't reside in the small blocks chain anymore.
+   */
+  StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
+
+  chainProperty.startingBlock = bbHeadOfChain;
+
+  StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
+
+  /*
+   * Destroy the temporary propertyless big block chain.
+   * Create a new big block chain associated with this property.
+   */
+  BlockChainStream_Destroy(bbTempChain);
+  bigBlockChain = BlockChainStream_Construct(This,
+                                             NULL,
+                                             propertyIndex);
+
+  return bigBlockChain;
+}
+
+/******************************************************************************
+** Storage32InternalImpl implementation
+*/
+
+StorageInternalImpl* StorageInternalImpl_Construct(
+  StorageImpl* ancestorStorage,  
+  ULONG          rootPropertyIndex)
+{
+  StorageInternalImpl* newStorage;
+
+  /*
+   * Allocate space for the new storage object
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
+
+  if (newStorage!=0)
+  {
+    memset(newStorage, 0, sizeof(StorageInternalImpl));
+
+    /*
+     * Initialize the virtual function table.
+     */
+    ICOM_VTBL(newStorage)    = &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;
+
+    return newStorage;
+  }
+
+  return 0;
+}
+
+void StorageInternalImpl_Destroy(
+  StorageInternalImpl* This)
+{
+  StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+**
+** Storage32InternalImpl_Commit
+**
+** The non-root storages cannot be opened in transacted mode thus this function
+** does nothing.
+*/
+HRESULT WINAPI StorageInternalImpl_Commit( 
+  IStorage*            iface,
+  DWORD                  grfCommitFlags)  /* [in] */ 
+{
+  return S_OK;
+}
+        
+/******************************************************************************
+**
+** Storage32InternalImpl_Revert
+**
+** The non-root storages cannot be opened in transacted mode thus this function
+** does nothing.
+*/
+HRESULT WINAPI StorageInternalImpl_Revert( 
+  IStorage*            iface)
+{
+  return S_OK;
+}
+
+/******************************************************************************
+** 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.
+     */
+    ICOM_VTBL(newEnumeration) = &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)
+{
+  IStorage_Release((IStorage*)This->parentStorage);
+  HeapFree(GetProcessHeap(), 0, This->stackToVisit);
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
+  IEnumSTATSTG*     iface,
+  REFIID            riid,
+  void**            ppvObject)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (ppvObject==0)
+    return E_INVALIDARG;
+
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = (IEnumSTATSTG*)This;
+  }
+  else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0) 
+  {
+    *ppvObject = (IEnumSTATSTG*)This;
+  }
+
+  /*
+   * 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;
+}
+        
+ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
+  IEnumSTATSTG* iface)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  This->ref++;
+  return This->ref;
+}
+        
+ULONG   WINAPI IEnumSTATSTGImpl_Release(
+  IEnumSTATSTG* iface)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  ULONG newRef;
+
+  This->ref--;
+  newRef = This->ref;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (newRef==0)
+  {
+    IEnumSTATSTGImpl_Destroy(This);
+  }
+
+  return newRef;;
+}
+
+HRESULT WINAPI IEnumSTATSTGImpl_Next(
+  IEnumSTATSTG* iface,
+  ULONG             celt,
+  STATSTG*          rgelt,
+  ULONG*            pceltFetched)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  StgProperty currentProperty;
+  STATSTG*    currentReturnStruct = rgelt;
+  ULONG       objectFetched       = 0;
+  ULONG      currentSearchNode;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
+    return E_INVALIDARG;  
+  
+  /*
+   * To avoid the special case, get another pointer to a ULONG value if
+   * the caller didn't supply one.
+   */
+  if (pceltFetched==0)
+    pceltFetched = &objectFetched;
+  
+  /*
+   * Start the iteration, we will iterate until we hit the end of the
+   * linked list or until we hit the number of items to iterate through
+   */
+  *pceltFetched = 0;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+
+  while ( ( *pceltFetched < celt) && 
+          ( currentSearchNode!=PROPERTY_NULL) )
+  {
+    /* 
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(This->parentStorage,
+      currentSearchNode, 
+      &currentProperty);
+
+    /*
+     * Copy the information to the return buffer.
+     */
+    StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
+      &currentProperty,
+      STATFLAG_DEFAULT);
+        
+    /*
+     * Step to the next item in the iteration
+     */
+    (*pceltFetched)++;
+    currentReturnStruct++;
+
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  if (*pceltFetched == celt)
+    return S_OK;
+
+  return S_FALSE;
+}
+
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Skip(
+  IEnumSTATSTG* iface,
+  ULONG             celt)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  StgProperty currentProperty;
+  ULONG       objectFetched       = 0;
+  ULONG       currentSearchNode;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+
+  while ( (objectFetched < celt) && 
+          (currentSearchNode!=PROPERTY_NULL) )
+  {
+    /* 
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(This->parentStorage,
+      currentSearchNode, 
+      &currentProperty);
+    
+    /*
+     * Step to the next item in the iteration
+     */
+    objectFetched++;
+
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  if (objectFetched == celt)
+    return S_OK;
+
+  return S_FALSE;
+}
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Reset(
+  IEnumSTATSTG* iface)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  StgProperty rootProperty;
+  BOOL      readSuccessful;
+
+  /*
+   * Re-initialize the search stack to an empty stack
+   */
+  This->stackSize = 0;
+
+  /*
+   * Read the root property from the storage.
+   */
+  readSuccessful = StorageImpl_ReadProperty(
+                    This->parentStorage,
+                    This->firstPropertyNode, 
+                    &rootProperty);
+
+  if (readSuccessful)
+  {
+    assert(rootProperty.sizeOfNameString!=0);
+
+    /*
+     * Push the search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
+  }
+
+  return S_OK;
+}
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Clone(
+  IEnumSTATSTG* iface,
+  IEnumSTATSTG**    ppenum)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  IEnumSTATSTGImpl* newClone;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (ppenum==0)
+    return E_INVALIDARG;
+  
+  newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
+               This->firstPropertyNode);
+
+  
+  /*
+   * The new clone enumeration must point to the same current node as
+   * the ole one.
+   */
+  newClone->stackSize    = This->stackSize    ;
+  newClone->stackMaxSize = This->stackMaxSize ;
+  newClone->stackToVisit = 
+    HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
+
+  memcpy(
+    newClone->stackToVisit, 
+    This->stackToVisit, 
+    sizeof(ULONG) * newClone->stackSize);
+
+  *ppenum = (IEnumSTATSTG*)newClone;
+
+  /*
+   * Don't forget to nail down a reference to the clone before
+   * returning it.
+   */
+  IEnumSTATSTGImpl_AddRef(*ppenum);
+
+  return S_OK;
+}
+
+INT IEnumSTATSTGImpl_FindParentProperty(
+  IEnumSTATSTGImpl *This,
+  ULONG             childProperty, 
+  StgProperty      *currentProperty,
+  ULONG            *thisNodeId)
+{
+  ULONG currentSearchNode;
+  ULONG foundNode;
+
+  /*
+   * To avoid the special case, get another pointer to a ULONG value if
+   * the caller didn't supply one.
+   */
+  if (thisNodeId==0)
+    thisNodeId = &foundNode;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  
+
+  while (currentSearchNode!=PROPERTY_NULL)
+  {
+    /*
+     * Store the current node in the returned parameters
+     */
+    *thisNodeId = currentSearchNode;
+
+    /* 
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(
+      This->parentStorage,
+      currentSearchNode, 
+      currentProperty);
+      
+    if (currentProperty->previousProperty == childProperty)
+      return PROPERTY_RELATION_PREVIOUS;
+
+    else if (currentProperty->nextProperty == childProperty)  
+      return PROPERTY_RELATION_NEXT;
+  
+    else if (currentProperty->dirProperty == childProperty)
+      return PROPERTY_RELATION_DIR;
+       
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  return PROPERTY_NULL;
+}
+
+ULONG IEnumSTATSTGImpl_FindProperty(
+  IEnumSTATSTGImpl* This,
+  const OLECHAR*  lpszPropName,
+  StgProperty*      currentProperty)
+{
+  ULONG currentSearchNode;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+
+  while (currentSearchNode!=PROPERTY_NULL)
+  {
+    /* 
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(This->parentStorage,
+      currentSearchNode, 
+      currentProperty);
+
+    if ( propertyNameCmp(
+          (OLECHAR*)currentProperty->name, 
+          (OLECHAR*)lpszPropName) == 0)
+      return currentSearchNode;
+
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  return PROPERTY_NULL;
+}
+
+void IEnumSTATSTGImpl_PushSearchNode(
+  IEnumSTATSTGImpl* This,
+  ULONG             nodeToPush)
+{
+  StgProperty rootProperty;
+  BOOL      readSuccessful;
+
+  /*
+   * First, make sure we're not trying to push an unexisting node.
+   */
+  if (nodeToPush==PROPERTY_NULL)
+    return;
+
+  /*
+   * First push the node to the stack
+   */
+  if (This->stackSize == This->stackMaxSize)
+  {
+    This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
+
+    This->stackToVisit = HeapReAlloc(
+                           GetProcessHeap(), 
+                           0,
+                           This->stackToVisit,
+                           sizeof(ULONG) * This->stackMaxSize);
+  }
+
+  This->stackToVisit[This->stackSize] = nodeToPush;
+  This->stackSize++;
+
+  /*
+   * Read the root property from the storage.
+   */
+  readSuccessful = StorageImpl_ReadProperty(
+                    This->parentStorage,
+                    nodeToPush, 
+                    &rootProperty);
+
+  if (readSuccessful)
+  {
+    assert(rootProperty.sizeOfNameString!=0);
+
+    /*
+     * Push the previous search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
+  }
+}
+
+ULONG IEnumSTATSTGImpl_PopSearchNode(
+  IEnumSTATSTGImpl* This,
+  BOOL            remove)
+{
+  ULONG topNode;
+
+  if (This->stackSize == 0)
+    return PROPERTY_NULL;
+
+  topNode = This->stackToVisit[This->stackSize-1];
+
+  if (remove)
+    This->stackSize--;
+
+  return topNode;
+}
+
+/******************************************************************************
+** StorageUtl implementation
+*/
+
+void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
+{
+  memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
+}
+
+void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
+{
+  memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
+}
+
+void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
+{
+  memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
+}
+
+void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
+{
+  memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
+}
+
+void StorageUtl_ReadGUID(void* 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));
+}
+
+void StorageUtl_WriteGUID(void* buffer, ULONG offset, 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));
+}
+
+void StorageUtl_CopyPropertyToSTATSTG(
+  STATSTG*     destination,
+  StgProperty* source,
+  int          statFlags)
+{
+  /*
+   * The copy of the string occurs only when the flag is not set
+   */
+  if ((statFlags & STATFLAG_NONAME) != 0)
+  {
+    destination->pwcsName = 0;
+  }
+  else
+  {
+    destination->pwcsName = 
+      CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
+
+    strcpyW((LPWSTR)destination->pwcsName, source->name);
+  }
+  
+  switch (source->propertyType)
+  {
+    case PROPTYPE_STORAGE:
+    case PROPTYPE_ROOT:
+      destination->type = STGTY_STORAGE;
+      break;
+    case PROPTYPE_STREAM:
+      destination->type = STGTY_STREAM;
+      break;
+    default:
+      destination->type = STGTY_STREAM;
+      break;        
+  }
+
+  destination->cbSize            = source->size;
+/*    
+  currentReturnStruct->mtime     = {0}; TODO
+  currentReturnStruct->ctime     = {0};
+  currentReturnStruct->atime     = {0}; 
+*/
+  destination->grfMode           = 0;
+  destination->grfLocksSupported = 0; 
+  destination->clsid             = source->propertyUniqueID;
+  destination->grfStateBits      = 0; 
+  destination->reserved          = 0; 
+}
+
+/******************************************************************************
+** BlockChainStream implementation
+*/
+
+BlockChainStream* BlockChainStream_Construct(
+  StorageImpl* parentStorage,  
+  ULONG*         headOfStreamPlaceHolder,
+  ULONG          propertyIndex)
+{
+  BlockChainStream* newStream;
+  ULONG blockIndex;
+
+  newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
+
+  newStream->parentStorage           = parentStorage;
+  newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
+  newStream->ownerPropertyIndex      = propertyIndex;
+  newStream->lastBlockNoInSequence   = 0xFFFFFFFF;
+  newStream->tailIndex               = BLOCK_END_OF_CHAIN;
+  newStream->numBlocks               = 0;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(newStream);
+
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    newStream->numBlocks++;
+    newStream->tailIndex = blockIndex;
+
+    blockIndex = StorageImpl_GetNextBlockInChain(
+                   parentStorage,
+                   blockIndex);
+  }
+
+  return newStream;
+}
+
+void BlockChainStream_Destroy(BlockChainStream* This)
+{
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ *      BlockChainStream_GetHeadOfChain
+ *
+ * Returns the head of this stream chain.
+ * Some special chains don't have properties, their heads are kept in
+ * This->headOfStreamPlaceHolder.
+ *
+ */
+ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
+{
+  StgProperty chainProperty;
+  BOOL      readSuccessful;
+
+  if (This->headOfStreamPlaceHolder != 0)
+    return *(This->headOfStreamPlaceHolder);
+
+  if (This->ownerPropertyIndex != PROPERTY_NULL)
+  {
+    readSuccessful = StorageImpl_ReadProperty(
+                      This->parentStorage,
+                      This->ownerPropertyIndex,
+                      &chainProperty);
+
+    if (readSuccessful)
+    {
+      return chainProperty.startingBlock;
+    }
+  }
+
+  return BLOCK_END_OF_CHAIN;
+}
+
+/******************************************************************************
+ *       BlockChainStream_GetCount
+ *
+ * Returns the number of blocks that comprises this chain.
+ * This is not the size of the stream as the last block may not be full!
+ * 
+ */
+ULONG BlockChainStream_GetCount(BlockChainStream* This)
+{
+  ULONG blockIndex;
+  ULONG count = 0;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(This);
+
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    count++;
+
+    blockIndex = StorageImpl_GetNextBlockInChain(
+                   This->parentStorage, 
+                   blockIndex);
+  }
+
+  return count;
+}
+
+/******************************************************************************
+ *      BlockChainStream_ReadAt 
+ *
+ * Reads a specified number of bytes from this chain at the specified offset.
+ * bytesRead may be NULL.
+ * Failure will be returned if the specified number of bytes has not been read.
+ */
+BOOL BlockChainStream_ReadAt(BlockChainStream* This,
+  ULARGE_INTEGER offset,
+  ULONG          size,
+  void*          buffer,
+  ULONG*         bytesRead)
+{
+  ULONG blockNoInSequence = offset.s.LowPart / This->parentStorage->bigBlockSize;
+  ULONG offsetInBlock     = offset.s.LowPart % This->parentStorage->bigBlockSize;
+  ULONG bytesToReadInBuffer;
+  ULONG blockIndex;
+  BYTE* bufferWalker;
+  BYTE* bigBlockBuffer;
+
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
+       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
+       (blockNoInSequence < This->lastBlockNoInSequence) )
+  {
+    blockIndex = BlockChainStream_GetHeadOfChain(This);
+    This->lastBlockNoInSequence = blockNoInSequence;
+  }
+  else
+  {
+    ULONG temp = blockNoInSequence;
+
+    blockIndex = This->lastBlockNoInSequenceIndex;
+    blockNoInSequence -= This->lastBlockNoInSequence;
+    This->lastBlockNoInSequence = temp;
+  }
+
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    blockIndex = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+    
+    blockNoInSequence--;
+  }
+
+  This->lastBlockNoInSequenceIndex = blockIndex;
+
+  /*
+   * Start reading the buffer.
+   */
+  *bytesRead   = 0;
+  bufferWalker = buffer;
+  
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy from this big block.
+     */
+    bytesToReadInBuffer = 
+      min(This->parentStorage->bigBlockSize - offsetInBlock, size);
+    
+    /*
+     * Copy those bytes to the buffer
+     */
+    bigBlockBuffer = 
+      StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
+    
+    memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
+    
+    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+    
+    /*
+     * Step to the next big block.
+     */
+    blockIndex    = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+
+    bufferWalker += bytesToReadInBuffer;
+    size         -= bytesToReadInBuffer;
+    *bytesRead   += bytesToReadInBuffer;
+    offsetInBlock = 0;  /* There is no offset on the next block */
+
+  }
+  
+  return (size == 0);
+}
+
+/******************************************************************************
+ *      BlockChainStream_WriteAt
+ *
+ * Writes the specified number of bytes to this chain at the specified offset.
+ * bytesWritten may be NULL.
+ * Will fail if not all specified number of bytes have been written.
+ */
+BOOL BlockChainStream_WriteAt(BlockChainStream* This,
+  ULARGE_INTEGER    offset,
+  ULONG             size,
+  const void*       buffer,
+  ULONG*            bytesWritten)
+{
+  ULONG blockNoInSequence = offset.s.LowPart / This->parentStorage->bigBlockSize;
+  ULONG offsetInBlock     = offset.s.LowPart % This->parentStorage->bigBlockSize;
+  ULONG bytesToWrite;
+  ULONG blockIndex;
+  BYTE* bufferWalker;
+  BYTE* bigBlockBuffer;
+
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
+       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
+       (blockNoInSequence < This->lastBlockNoInSequence) )
+  {
+    blockIndex = BlockChainStream_GetHeadOfChain(This);
+    This->lastBlockNoInSequence = blockNoInSequence;
+  }
+  else
+  {
+    ULONG temp = blockNoInSequence;
+
+    blockIndex = This->lastBlockNoInSequenceIndex;
+    blockNoInSequence -= This->lastBlockNoInSequence;
+    This->lastBlockNoInSequence = temp;
+  }
+
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    blockIndex = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+    
+    blockNoInSequence--;
+  }
+
+  This->lastBlockNoInSequenceIndex = blockIndex;
+
+  /*
+   * Here, I'm casting away the constness on the buffer variable
+   * This is OK since we don't intend to modify that buffer.
+   */
+  *bytesWritten   = 0;
+  bufferWalker = (BYTE*)buffer;
+
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy from this big block.
+     */
+    bytesToWrite = 
+      min(This->parentStorage->bigBlockSize - offsetInBlock, size);
+    
+    /*
+     * Copy those bytes to the buffer
+     */
+    bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
+    
+    memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
+    
+    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+    
+    /*
+     * Step to the next big block.
+     */
+    blockIndex    = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+
+    bufferWalker  += bytesToWrite;
+    size          -= bytesToWrite;
+    *bytesWritten += bytesToWrite;
+    offsetInBlock  = 0;      /* There is no offset on the next block */
+  }
+  
+  return (size == 0);
+}
+
+/******************************************************************************
+ *      BlockChainStream_Shrink
+ *
+ * Shrinks this chain in the big block depot.
+ */
+BOOL BlockChainStream_Shrink(BlockChainStream* This,
+                               ULARGE_INTEGER    newSize)
+{
+  ULONG blockIndex, extraBlock;
+  ULONG numBlocks;
+  ULONG count = 1;
+
+  /*
+   * Reset the last accessed block cache.
+   */
+  This->lastBlockNoInSequence = 0xFFFFFFFF;
+  This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
+
+  /*
+   * Figure out how many blocks are needed to contain the new size
+   */
+  numBlocks = newSize.s.LowPart / This->parentStorage->bigBlockSize;
+
+  if ((newSize.s.LowPart % This->parentStorage->bigBlockSize) != 0)
+    numBlocks++;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Go to the new end of chain
+   */
+  while (count < numBlocks)
+  {
+    blockIndex = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+
+    count++;
+  }
+
+  /* Get the next block before marking the new end */
+  extraBlock = 
+    StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+
+  /* Mark the new end of chain */
+  StorageImpl_SetNextBlockInChain(
+    This->parentStorage, 
+    blockIndex, 
+    BLOCK_END_OF_CHAIN);
+
+  This->tailIndex = blockIndex;
+  This->numBlocks = numBlocks;
+
+  /*
+   * Mark the extra blocks as free
+   */
+  while (extraBlock != BLOCK_END_OF_CHAIN)
+  {
+    blockIndex = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
+
+    StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
+    extraBlock = blockIndex;
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BlockChainStream_Enlarge
+ *
+ * Grows this chain in the big block depot.
+ */
+BOOL BlockChainStream_Enlarge(BlockChainStream* This,
+                                ULARGE_INTEGER    newSize)
+{
+  ULONG blockIndex, currentBlock;
+  ULONG newNumBlocks;
+  ULONG oldNumBlocks = 0;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Empty chain. Create the head.
+   */
+  if (blockIndex == BLOCK_END_OF_CHAIN)
+  {
+    blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+    StorageImpl_SetNextBlockInChain(This->parentStorage,
+                                      blockIndex,
+                                      BLOCK_END_OF_CHAIN);
+
+    if (This->headOfStreamPlaceHolder != 0)
+    {
+      *(This->headOfStreamPlaceHolder) = blockIndex;
+    }
+    else
+    {
+      StgProperty chainProp;
+      assert(This->ownerPropertyIndex != PROPERTY_NULL);
+
+      StorageImpl_ReadProperty(
+        This->parentStorage, 
+        This->ownerPropertyIndex,
+        &chainProp);
+
+      chainProp.startingBlock = blockIndex; 
+
+      StorageImpl_WriteProperty(
+        This->parentStorage, 
+        This->ownerPropertyIndex,
+        &chainProp);
+    }
+
+    This->tailIndex = blockIndex;
+    This->numBlocks = 1;
+  }
+
+  /*
+   * Figure out how many blocks are needed to contain this stream
+   */
+  newNumBlocks = newSize.s.LowPart / This->parentStorage->bigBlockSize;
+
+  if ((newSize.s.LowPart % This->parentStorage->bigBlockSize) != 0)
+    newNumBlocks++;
+
+  /*
+   * Go to the current end of chain
+   */
+  if (This->tailIndex == BLOCK_END_OF_CHAIN)
+  {
+    currentBlock = blockIndex;
+
+    while (blockIndex != BLOCK_END_OF_CHAIN)
+    {
+      This->numBlocks++;
+      currentBlock = blockIndex;
+
+      blockIndex =
+        StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
+    }
+
+    This->tailIndex = currentBlock;
+  }
+
+  currentBlock = This->tailIndex;
+  oldNumBlocks = This->numBlocks;
+
+  /*
+   * Add new blocks to the chain
+   */
+  if (oldNumBlocks < newNumBlocks)
+  {
+    while (oldNumBlocks < newNumBlocks)
+    {
+      blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+
+      StorageImpl_SetNextBlockInChain(
+	This->parentStorage, 
+	currentBlock, 
+	blockIndex);
+
+      StorageImpl_SetNextBlockInChain(
+        This->parentStorage, 
+	blockIndex, 
+	BLOCK_END_OF_CHAIN);
+
+      currentBlock = blockIndex;
+      oldNumBlocks++;
+    }
+
+    This->tailIndex = blockIndex;
+    This->numBlocks = newNumBlocks;
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BlockChainStream_SetSize
+ *
+ * Sets the size of this stream. The big block depot will be updated.
+ * The file will grow if we grow the chain.
+ *
+ * TODO: Free the actual blocks in the file when we shrink the chain.
+ *       Currently, the blocks are still in the file. So the file size
+ *       doesn't shrink even if we shrink streams. 
+ */
+BOOL BlockChainStream_SetSize(
+  BlockChainStream* This,
+  ULARGE_INTEGER    newSize)
+{
+  ULARGE_INTEGER size = BlockChainStream_GetSize(This);
+
+  if (newSize.s.LowPart == size.s.LowPart)
+    return TRUE;
+
+  if (newSize.s.LowPart < size.s.LowPart)
+  {
+    BlockChainStream_Shrink(This, newSize);
+  }
+  else
+  {
+    ULARGE_INTEGER fileSize = 
+      BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
+
+    ULONG diff = newSize.s.LowPart - size.s.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.s.LowPart += diff;
+    BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
+
+    BlockChainStream_Enlarge(This, newSize);
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BlockChainStream_GetSize
+ *
+ * Returns the size of this chain.
+ * Will return the block count if this chain doesn't have a property.
+ */
+ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
+{
+  StgProperty chainProperty;
+
+  if(This->headOfStreamPlaceHolder == NULL)
+  {
+    /* 
+     * This chain is a data stream read the property and return 
+     * the appropriate size
+     */
+    StorageImpl_ReadProperty(
+      This->parentStorage,
+      This->ownerPropertyIndex,
+      &chainProperty);
+
+    return chainProperty.size;
+  }
+  else
+  {
+    /*
+     * this chain is a chain that does not have a property, figure out the 
+     * size by making the product number of used blocks times the 
+     * size of them
+     */
+    ULARGE_INTEGER result;
+    result.s.HighPart = 0;
+
+    result.s.LowPart  = 
+      BlockChainStream_GetCount(This) * 
+      This->parentStorage->bigBlockSize;
+
+    return result;
+  }
+}
+
+/******************************************************************************
+** SmallBlockChainStream implementation
+*/
+
+SmallBlockChainStream* SmallBlockChainStream_Construct(
+  StorageImpl* parentStorage,  
+  ULONG          propertyIndex)
+{
+  SmallBlockChainStream* newStream;
+
+  newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
+
+  newStream->parentStorage      = parentStorage;
+  newStream->ownerPropertyIndex = propertyIndex;
+
+  return newStream;
+}
+
+void SmallBlockChainStream_Destroy(
+  SmallBlockChainStream* This)
+{
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetHeadOfChain
+ *
+ * Returns the head of this chain of small blocks.
+ */
+ULONG SmallBlockChainStream_GetHeadOfChain(
+  SmallBlockChainStream* This)
+{
+  StgProperty chainProperty;
+  BOOL      readSuccessful;
+
+  if (This->ownerPropertyIndex)
+  {
+    readSuccessful = StorageImpl_ReadProperty(
+                      This->parentStorage,
+                      This->ownerPropertyIndex,
+                      &chainProperty);
+
+    if (readSuccessful)
+    {
+      return chainProperty.startingBlock;
+    }
+
+  }
+
+  return BLOCK_END_OF_CHAIN;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetNextBlockInChain
+ *
+ * Returns the index of the next small block in this chain.
+ * 
+ * Return Values:
+ *    - BLOCK_END_OF_CHAIN: end of this chain
+ *    - BLOCK_UNUSED: small block 'blockIndex' is free
+ */
+ULONG SmallBlockChainStream_GetNextBlockInChain(
+  SmallBlockChainStream* This,
+  ULONG                  blockIndex)
+{
+  ULARGE_INTEGER offsetOfBlockInDepot;
+  DWORD  buffer;
+  ULONG  nextBlockInChain = BLOCK_END_OF_CHAIN;
+  ULONG  bytesRead;
+  BOOL success;
+
+  offsetOfBlockInDepot.s.HighPart = 0;
+  offsetOfBlockInDepot.s.LowPart  = blockIndex * sizeof(ULONG);
+
+  /*
+   * Read those bytes in the buffer from the small block file.
+   */
+  success = BlockChainStream_ReadAt(
+              This->parentStorage->smallBlockDepotChain,
+              offsetOfBlockInDepot,
+              sizeof(DWORD),
+              &buffer,
+              &bytesRead);
+
+  if (success)
+  {
+    StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
+  }
+
+  return nextBlockInChain;
+}
+
+/******************************************************************************
+ *       SmallBlockChainStream_SetNextBlockInChain
+ *
+ * Writes the index of the next block of the specified block in the small
+ * block depot.
+ * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
+ * To flag a block as free use BLOCK_UNUSED as nextBlock.
+ */
+void SmallBlockChainStream_SetNextBlockInChain(
+  SmallBlockChainStream* This,
+  ULONG                  blockIndex,
+  ULONG                  nextBlock)
+{
+  ULARGE_INTEGER offsetOfBlockInDepot;
+  DWORD  buffer;
+  ULONG  bytesWritten;
+
+  offsetOfBlockInDepot.s.HighPart = 0;
+  offsetOfBlockInDepot.s.LowPart  = blockIndex * sizeof(ULONG);
+
+  StorageUtl_WriteDWord(&buffer, 0, nextBlock);
+
+  /*
+   * Read those bytes in the buffer from the small block file.
+   */
+  BlockChainStream_WriteAt(
+    This->parentStorage->smallBlockDepotChain,
+    offsetOfBlockInDepot,
+    sizeof(DWORD),
+    &buffer,
+    &bytesWritten);
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_FreeBlock
+ *
+ * Flag small block 'blockIndex' as free in the small block depot.
+ */
+void SmallBlockChainStream_FreeBlock(
+  SmallBlockChainStream* This,
+  ULONG                  blockIndex)
+{
+  SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetNextFreeBlock
+ *
+ * Returns the index of a free small block. The small block depot will be
+ * enlarged if necessary. The small block chain will also be enlarged if
+ * necessary.
+ */
+ULONG SmallBlockChainStream_GetNextFreeBlock(
+  SmallBlockChainStream* This)
+{
+  ULARGE_INTEGER offsetOfBlockInDepot;
+  DWORD buffer;
+  ULONG bytesRead;
+  ULONG blockIndex = 0;
+  ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
+  BOOL success = TRUE;
+  ULONG smallBlocksPerBigBlock;
+
+  offsetOfBlockInDepot.s.HighPart = 0;
+
+  /*
+   * Scan the small block depot for a free block
+   */
+  while (nextBlockIndex != BLOCK_UNUSED)
+  {
+    offsetOfBlockInDepot.s.LowPart = blockIndex * sizeof(ULONG);
+
+    success = BlockChainStream_ReadAt(
+                This->parentStorage->smallBlockDepotChain,
+                offsetOfBlockInDepot,
+                sizeof(DWORD),
+                &buffer,
+                &bytesRead);
+
+    /*
+     * If we run out of space for the small block depot, enlarge it
+     */
+    if (success)
+    {
+      StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
+
+      if (nextBlockIndex != BLOCK_UNUSED)
+        blockIndex++;
+    }
+    else
+    {
+      ULONG count = 
+        BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
+
+      ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
+      ULONG nextBlock, newsbdIndex;
+      BYTE* smallBlockDepot;
+
+      nextBlock = sbdIndex;
+      while (nextBlock != BLOCK_END_OF_CHAIN)
+      {
+        sbdIndex = nextBlock;
+        nextBlock = 
+          StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
+      }
+
+      newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+      if (sbdIndex != BLOCK_END_OF_CHAIN)
+        StorageImpl_SetNextBlockInChain(
+          This->parentStorage, 
+          sbdIndex, 
+          newsbdIndex);
+
+      StorageImpl_SetNextBlockInChain(
+        This->parentStorage, 
+        newsbdIndex, 
+        BLOCK_END_OF_CHAIN);
+
+      /*
+       * Initialize all the small blocks to free
+       */
+      smallBlockDepot = 
+        StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
+
+      memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
+      StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
+
+      if (count == 0)
+      {
+        /*
+         * We have just created the small block depot.
+         */
+        StgProperty rootProp;
+        ULONG sbStartIndex; 
+
+        /*
+         * Save it in the header
+         */
+        This->parentStorage->smallBlockDepotStart = newsbdIndex;
+        StorageImpl_SaveFileHeader(This->parentStorage);
+
+        /*
+         * And allocate the first big block that will contain small blocks 
+         */
+        sbStartIndex = 
+          StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+
+        StorageImpl_SetNextBlockInChain(
+          This->parentStorage, 
+          sbStartIndex, 
+          BLOCK_END_OF_CHAIN);
+
+        StorageImpl_ReadProperty(
+          This->parentStorage, 
+          This->parentStorage->rootPropertySetIndex, 
+          &rootProp);
+
+        rootProp.startingBlock = sbStartIndex;
+        rootProp.size.s.HighPart = 0;
+        rootProp.size.s.LowPart  = This->parentStorage->bigBlockSize;
+
+        StorageImpl_WriteProperty(
+          This->parentStorage, 
+          This->parentStorage->rootPropertySetIndex, 
+          &rootProp);
+      }
+    }
+  }
+
+  smallBlocksPerBigBlock = 
+    This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
+
+  /*
+   * Verify if we have to allocate big blocks to contain small blocks
+   */
+  if (blockIndex % smallBlocksPerBigBlock == 0)
+  {
+    StgProperty rootProp;
+    ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
+
+    StorageImpl_ReadProperty(
+      This->parentStorage, 
+      This->parentStorage->rootPropertySetIndex, 
+      &rootProp);
+
+    if (rootProp.size.s.LowPart < 
+       (blocksRequired * This->parentStorage->bigBlockSize))
+    {
+      rootProp.size.s.LowPart += This->parentStorage->bigBlockSize;
+
+      BlockChainStream_SetSize(
+        This->parentStorage->smallBlockRootChain, 
+        rootProp.size);
+
+      StorageImpl_WriteProperty(
+        This->parentStorage, 
+        This->parentStorage->rootPropertySetIndex, 
+        &rootProp);
+    }
+  }
+
+  return blockIndex;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_ReadAt
+ *
+ * Reads a specified number of bytes from this chain at the specified offset.
+ * bytesRead may be NULL.
+ * Failure will be returned if the specified number of bytes has not been read. 
+ */
+BOOL SmallBlockChainStream_ReadAt(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER         offset,
+  ULONG                  size,
+  void*                  buffer,
+  ULONG*                 bytesRead)
+{
+  ULARGE_INTEGER offsetInBigBlockFile;
+  ULONG blockNoInSequence = 
+    offset.s.LowPart / This->parentStorage->smallBlockSize;
+
+  ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->smallBlockSize;
+  ULONG bytesToReadInBuffer;
+  ULONG blockIndex;
+  ULONG bytesReadFromBigBlockFile;
+  BYTE* bufferWalker;
+
+  /*
+   * This should never happen on a small block file.
+   */
+  assert(offset.s.HighPart==0);
+
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+
+    blockNoInSequence--;
+  }
+
+  /*
+   * Start reading the buffer.
+   */
+  *bytesRead   = 0;
+  bufferWalker = buffer;
+
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy from this small block.
+     */
+    bytesToReadInBuffer = 
+      min(This->parentStorage->smallBlockSize - offsetInBlock, size);
+
+    /*
+     * Calculate the offset of the small block in the small block file.
+     */
+    offsetInBigBlockFile.s.HighPart  = 0;
+    offsetInBigBlockFile.s.LowPart   = 
+      blockIndex * This->parentStorage->smallBlockSize;
+
+    offsetInBigBlockFile.s.LowPart  += offsetInBlock;
+
+    /*
+     * Read those bytes in the buffer from the small block file.
+     */
+    BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
+      offsetInBigBlockFile,
+      bytesToReadInBuffer,
+      bufferWalker,
+      &bytesReadFromBigBlockFile);
+
+    assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
+
+    /*
+     * Step to the next big block.
+     */
+    blockIndex    = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+    bufferWalker += bytesToReadInBuffer;
+    size         -= bytesToReadInBuffer;
+    *bytesRead   += bytesToReadInBuffer;
+    offsetInBlock = 0;  /* There is no offset on the next block */
+  }
+
+  return (size == 0);
+}
+
+/******************************************************************************
+ *       SmallBlockChainStream_WriteAt
+ *
+ * Writes the specified number of bytes to this chain at the specified offset.
+ * bytesWritten may be NULL.
+ * Will fail if not all specified number of bytes have been written.
+ */
+BOOL SmallBlockChainStream_WriteAt(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER offset,
+  ULONG          size,
+  const void*    buffer,
+  ULONG*         bytesWritten)
+{
+  ULARGE_INTEGER offsetInBigBlockFile;
+  ULONG blockNoInSequence = 
+    offset.s.LowPart / This->parentStorage->smallBlockSize;
+
+  ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->smallBlockSize;
+  ULONG bytesToWriteInBuffer;
+  ULONG blockIndex;
+  ULONG bytesWrittenFromBigBlockFile;
+  BYTE* bufferWalker;
+  
+  /*
+   * This should never happen on a small block file.
+   */
+  assert(offset.s.HighPart==0);
+  
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+  
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+    
+    blockNoInSequence--;
+  }
+  
+  /*
+   * Start writing the buffer.
+   *
+   * Here, I'm casting away the constness on the buffer variable
+   * This is OK since we don't intend to modify that buffer.
+   */
+  *bytesWritten   = 0;
+  bufferWalker = (BYTE*)buffer;
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy to this small block.
+     */
+    bytesToWriteInBuffer = 
+      min(This->parentStorage->smallBlockSize - offsetInBlock, size);
+    
+    /*
+     * Calculate the offset of the small block in the small block file.
+     */
+    offsetInBigBlockFile.s.HighPart  = 0;
+    offsetInBigBlockFile.s.LowPart   = 
+      blockIndex * This->parentStorage->smallBlockSize;
+
+    offsetInBigBlockFile.s.LowPart  += offsetInBlock;
+    
+    /*
+     * Write those bytes in the buffer to the small block file.
+     */
+    BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
+      offsetInBigBlockFile,
+      bytesToWriteInBuffer,
+      bufferWalker,
+      &bytesWrittenFromBigBlockFile);
+    
+    assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
+    
+    /*
+     * Step to the next big block.
+     */
+    blockIndex    = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+    bufferWalker  += bytesToWriteInBuffer;
+    size          -= bytesToWriteInBuffer;
+    *bytesWritten += bytesToWriteInBuffer;
+    offsetInBlock  = 0;     /* There is no offset on the next block */
+  }
+  
+  return (size == 0);
+}
+
+/******************************************************************************
+ *       SmallBlockChainStream_Shrink
+ *
+ * Shrinks this chain in the small block depot. 
+ */
+BOOL SmallBlockChainStream_Shrink(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER newSize)
+{
+  ULONG blockIndex, extraBlock;
+  ULONG numBlocks;
+  ULONG count = 0;
+
+  numBlocks = newSize.s.LowPart / This->parentStorage->smallBlockSize;
+
+  if ((newSize.s.LowPart % This->parentStorage->smallBlockSize) != 0)
+    numBlocks++;
+
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Go to the new end of chain
+   */
+  while (count < numBlocks)
+  {
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+    count++;
+  }
+
+  /*
+   * If the count is 0, we have a special case, the head of the chain was
+   * just freed. 
+   */
+  if (count == 0)
+  {
+    StgProperty chainProp;
+
+    StorageImpl_ReadProperty(This->parentStorage, 
+			     This->ownerPropertyIndex,
+			     &chainProp);
+
+    chainProp.startingBlock = BLOCK_END_OF_CHAIN;
+
+    StorageImpl_WriteProperty(This->parentStorage,
+			      This->ownerPropertyIndex,
+			      &chainProp);
+
+    /*
+     * We start freeing the chain at the head block.
+     */
+    extraBlock = blockIndex;
+  }
+  else
+  {
+    /* Get the next block before marking the new end */
+    extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+
+    /* Mark the new end of chain */
+    SmallBlockChainStream_SetNextBlockInChain(
+      This, 
+      blockIndex, 
+      BLOCK_END_OF_CHAIN);
+  }
+
+  /*
+   * Mark the extra blocks as free
+   */
+  while (extraBlock != BLOCK_END_OF_CHAIN)
+  {
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
+    SmallBlockChainStream_FreeBlock(This, extraBlock);
+    extraBlock = blockIndex;
+  }
+
+  return TRUE;  
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_Enlarge
+ *
+ * Grows this chain in the small block depot.
+ */
+BOOL SmallBlockChainStream_Enlarge(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER newSize)
+{
+  ULONG blockIndex, currentBlock;
+  ULONG newNumBlocks;
+  ULONG oldNumBlocks = 0;
+
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Empty chain
+   */
+  if (blockIndex == BLOCK_END_OF_CHAIN)
+  {
+
+    StgProperty chainProp;
+
+    StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
+                               &chainProp);
+
+    chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
+
+    StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
+                                &chainProp);
+
+    blockIndex = chainProp.startingBlock;
+    SmallBlockChainStream_SetNextBlockInChain(
+      This, 
+      blockIndex, 
+      BLOCK_END_OF_CHAIN);
+  }
+
+  currentBlock = blockIndex;
+
+  /*
+   * Figure out how many blocks are needed to contain this stream
+   */
+  newNumBlocks = newSize.s.LowPart / This->parentStorage->smallBlockSize;
+
+  if ((newSize.s.LowPart % This->parentStorage->smallBlockSize) != 0)
+    newNumBlocks++;
+
+  /*
+   * Go to the current end of chain
+   */
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    oldNumBlocks++;
+    currentBlock = blockIndex;
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
+  }
+
+  /*
+   * Add new blocks to the chain
+   */
+  while (oldNumBlocks < newNumBlocks)
+  {
+    blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
+    SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
+
+    SmallBlockChainStream_SetNextBlockInChain(
+      This, 
+      blockIndex, 
+      BLOCK_END_OF_CHAIN);
+
+    currentBlock = blockIndex;
+    oldNumBlocks++;
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetCount
+ *
+ * Returns the number of blocks that comprises this chain.
+ * This is not the size of this chain as the last block may not be full!
+ */
+ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
+{
+  ULONG blockIndex;
+  ULONG count = 0;
+
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    count++;
+
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+  }
+
+  return count;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_SetSize
+ *
+ * Sets the size of this stream.
+ * The file will grow if we grow the chain.
+ *
+ * TODO: Free the actual blocks in the file when we shrink the chain.
+ *       Currently, the blocks are still in the file. So the file size
+ *       doesn't shrink even if we shrink streams. 
+ */
+BOOL SmallBlockChainStream_SetSize(
+                SmallBlockChainStream* This,
+                ULARGE_INTEGER    newSize)
+{
+  ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
+
+  if (newSize.s.LowPart == size.s.LowPart)
+    return TRUE;
+
+  if (newSize.s.LowPart < size.s.LowPart)
+  {
+    SmallBlockChainStream_Shrink(This, newSize);
+  }
+  else
+  {
+    SmallBlockChainStream_Enlarge(This, newSize);
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetSize
+ *
+ * Returns the size of this chain.
+ */
+ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
+{
+  StgProperty chainProperty;
+
+  StorageImpl_ReadProperty(
+    This->parentStorage,
+    This->ownerPropertyIndex,
+    &chainProperty);
+
+  return chainProperty.size;
+}
+
+/******************************************************************************
+ *    StgCreateDocfile  [OLE32.144]
+ */
+HRESULT WINAPI StgCreateDocfile(
+  LPCOLESTR pwcsName,
+  DWORD       grfMode,
+  DWORD       reserved,
+  IStorage  **ppstgOpen)
+{
+  StorageImpl* newStorage = 0;
+  HANDLE       hFile      = INVALID_HANDLE_VALUE;
+  HRESULT        hr         = S_OK;
+  DWORD          shareMode;
+  DWORD          accessMode;
+  DWORD          creationMode;
+  DWORD          fileAttributes;
+  WCHAR          tempFileName[MAX_PATH];
+
+  TRACE("(%s, %lx, %ld, %p)\n", 
+	debugstr_w(pwcsName), grfMode, 
+	reserved, ppstgOpen);
+
+  /*
+   * Validate the parameters
+   */
+  if (ppstgOpen == 0)
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * Generate a unique name.
+   */
+  if (pwcsName == 0)
+  {
+    WCHAR tempPath[MAX_PATH];
+    WCHAR prefix[] = { 'S', 'T', 'O', 0 };
+
+    memset(tempPath, 0, sizeof(tempPath));
+    memset(tempFileName, 0, sizeof(tempFileName));
+
+    if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
+      tempPath[0] = '.';
+
+    if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
+      pwcsName = tempFileName;
+    else
+      return STG_E_INSUFFICIENTMEMORY;
+  }
+
+  /*
+   * Interpret the STGM value grfMode 
+   */
+  shareMode    = GetShareModeFromSTGM(grfMode);
+  accessMode   = GetAccessModeFromSTGM(grfMode);
+  creationMode = GetCreationModeFromSTGM(grfMode);
+
+  if (grfMode & STGM_DELETEONRELEASE)
+    fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
+  else
+    fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
+
+  if (grfMode & STGM_TRANSACTED)
+    FIXME("Transacted mode not implemented.\n");
+
+  /*
+   * Initialize the "out" parameter.
+   */
+  *ppstgOpen = 0;
+
+  hFile = CreateFileW(pwcsName,
+                        accessMode,
+                        shareMode,
+            NULL,
+                        creationMode,
+                        fileAttributes,
+            0);
+ 
+  if (hFile == INVALID_HANDLE_VALUE)
+  {
+    return E_FAIL;
+  }
+
+  /*
+   * Allocate and initialize the new IStorage32object.
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+ 
+  if (newStorage == 0)
+    return STG_E_INSUFFICIENTMEMORY;
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         hFile,
+         NULL,
+         grfMode,
+         TRUE,
+         TRUE);
+ 
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    return hr;
+  }
+
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+
+  return hr;
+}
+
+/******************************************************************************
+ *              StgOpenStorage        [OLE32.148]
+ */
+HRESULT WINAPI StgOpenStorage(
+  const OLECHAR *pwcsName,
+  IStorage      *pstgPriority,
+  DWORD           grfMode,
+  SNB           snbExclude,
+  DWORD           reserved, 
+  IStorage      **ppstgOpen)
+{
+  StorageImpl* newStorage = 0;
+  HRESULT        hr = S_OK;
+  HANDLE       hFile = 0;
+  DWORD          shareMode;
+  DWORD          accessMode;
+
+  TRACE("(%s, %p, %lx, %p, %ld, %p)\n", 
+	debugstr_w(pwcsName), pstgPriority, grfMode,
+	snbExclude, reserved, ppstgOpen);
+
+  /*
+   * Perform a sanity check
+   */
+  if (( pwcsName == 0) || (ppstgOpen == 0) )
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * Interpret the STGM value grfMode
+   */
+  shareMode    = GetShareModeFromSTGM(grfMode);
+  accessMode   = GetAccessModeFromSTGM(grfMode);
+
+  /*
+   * Initialize the "out" parameter.
+   */
+  *ppstgOpen = 0;
+  
+  hFile = CreateFileW( pwcsName, 
+                       accessMode,
+                       shareMode,
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+                       0);
+  
+  
+  if (hFile==INVALID_HANDLE_VALUE)
+  {
+    HRESULT hr = E_FAIL;
+    DWORD last_error = GetLastError();
+
+    switch (last_error)
+    {
+      case ERROR_FILE_NOT_FOUND:
+        hr = STG_E_FILENOTFOUND;
+        break;
+
+      case ERROR_PATH_NOT_FOUND:
+        hr = STG_E_PATHNOTFOUND;
+        break;
+
+      case ERROR_ACCESS_DENIED:
+      case ERROR_WRITE_PROTECT:
+        hr = STG_E_ACCESSDENIED;
+        break;
+
+      case ERROR_SHARING_VIOLATION:
+        hr = STG_E_SHAREVIOLATION;
+        break;
+
+      default:
+        hr = E_FAIL;
+    }
+
+    return hr;
+  }
+
+  /*
+   * Allocate and initialize the new IStorage32object.
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+  
+  if (newStorage == 0)
+    return STG_E_INSUFFICIENTMEMORY;
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         hFile,
+         NULL,
+         grfMode,
+         TRUE,
+         FALSE);
+  
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    return hr;
+  }
+  
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+  
+  return hr;
+}
+
+/******************************************************************************
+ *    StgCreateDocfileOnILockBytes    [OLE32.145]
+ */
+HRESULT WINAPI StgCreateDocfileOnILockBytes(
+      ILockBytes *plkbyt,
+      DWORD grfMode,
+      DWORD reserved,
+      IStorage** ppstgOpen)
+{
+  StorageImpl*   newStorage = 0;
+  HRESULT        hr         = S_OK;
+
+  /*
+   * Validate the parameters
+   */
+  if ((ppstgOpen == 0) || (plkbyt == 0))
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Allocate and initialize the new IStorage object.
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+
+  if (newStorage == 0)
+    return STG_E_INSUFFICIENTMEMORY;
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         0,
+         plkbyt,
+         grfMode,
+         FALSE,
+         TRUE);
+
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    return hr;
+  }
+
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+
+  return hr;  
+}
+
+/******************************************************************************
+ *    StgOpenStorageOnILockBytes    [OLE32.149]
+ */
+HRESULT WINAPI StgOpenStorageOnILockBytes(
+      ILockBytes *plkbyt,
+      IStorage *pstgPriority,
+      DWORD grfMode,
+      SNB snbExclude,
+      DWORD reserved,
+      IStorage **ppstgOpen)
+{
+  StorageImpl* newStorage = 0;
+  HRESULT        hr = S_OK;
+
+  /*
+   * Perform a sanity check
+   */
+  if ((plkbyt == 0) || (ppstgOpen == 0))
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * Initialize the "out" parameter.
+   */
+  *ppstgOpen = 0;
+
+  /*
+   * Allocate and initialize the new IStorage object.
+   */
+  newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+ 
+  if (newStorage == 0)
+    return STG_E_INSUFFICIENTMEMORY;
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         0,
+         plkbyt,
+         grfMode,
+         FALSE,
+         FALSE);
+
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    return hr;
+  }
+
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+
+  return hr;
+}
+#ifndef __WIN32OS2__
+/******************************************************************************
+ *              StgSetTimes [ole32.150]
+ *
+ *
+ */
+HRESULT WINAPI StgSetTimes(WCHAR * str, FILETIME * a, FILETIME * b, FILETIME *c )
+{
+ 
+  FIXME("(%p, %p, %p, %p),stub!\n", str, a, b, c);
+  return FALSE;
+}
+#endif
+
+/******************************************************************************
+ *              StgIsStorageILockBytes        [OLE32.147]
+ *
+ * Determines if the ILockBytes contains a storage object.
+ */
+HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
+{
+  BYTE sig[8];
+  ULARGE_INTEGER offset;
+
+  offset.s.HighPart = 0;
+  offset.s.LowPart  = 0;
+
+  ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
+
+  if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
+    return S_OK;
+
+  return S_FALSE;
+}
+
+/******************************************************************************
+ *              WriteClassStg        [OLE32.158]
+ *
+ * This method will store the specified CLSID in the specified storage object
+ */
+HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
+{
+  HRESULT hRes;
+
+  assert(pStg != 0);
+
+  hRes = IStorage_SetClass(pStg, rclsid);
+
+  return hRes;
+}
+
+/***********************************************************************
+ *    ReadClassStg
+ *
+ * This method reads the CLSID previously written to a storage object with the WriteClassStg.
+ */
+HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
+
+    STATSTG pstatstg;
+    HRESULT hRes;
+    
+    TRACE("()\n");
+
+    if(pclsid==NULL)
+        return E_POINTER;
+   /*
+    * read a STATSTG structure (contains the clsid) from the storage
+    */
+    hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
+
+    if(SUCCEEDED(hRes))
+        *pclsid=pstatstg.clsid;
+
+    return hRes;
+}
+
+/***********************************************************************
+ *    OleLoadFromStream
+ *
+ * This function loads an object from stream
+ */
+HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
+{
+    CLSID	clsid;
+    HRESULT	res;
+    LPPERSISTSTREAM	xstm;
+
+    TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
+
+    res=ReadClassStm(pStm,&clsid);
+    if (!SUCCEEDED(res))
+	return res;
+    res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
+    if (!SUCCEEDED(res))
+	return res;
+    res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
+    if (!SUCCEEDED(res)) {
+	IUnknown_Release((IUnknown*)*ppvObj);
+	return res;
+    }
+    res=IPersistStream_Load(xstm,pStm);
+    IPersistStream_Release(xstm);
+    /* FIXME: all refcounts ok at this point? I think they should be:
+     * 		pStm	: unchanged
+     *		ppvObj	: 1
+     *		xstm	: 0 (released)
+     */
+    return res;
+}
+
+/***********************************************************************
+ *    OleSaveToStream
+ *
+ * This function saves an object with the IPersistStream interface on it
+ * to the specified stream.
+ */
+HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
+{
+
+    CLSID clsid;
+    HRESULT res;
+    
+    TRACE("(%p,%p)\n",pPStm,pStm);
+
+    res=IPersistStream_GetClassID(pPStm,&clsid);
+
+    if (SUCCEEDED(res)){
+        
+        res=WriteClassStm(pStm,&clsid);
+
+        if (SUCCEEDED(res))
+
+            res=IPersistStream_Save(pPStm,pStm,TRUE);
+    }
+
+    TRACE("Finished Save\n");
+    return res;
+}
+
+/****************************************************************************
+ * This method validate a STGM parameter that can contain the values below
+ *
+ * STGM_DIRECT               0x00000000
+ * STGM_TRANSACTED           0x00010000
+ * STGM_SIMPLE               0x08000000
+ * 
+ * STGM_READ                 0x00000000
+ * STGM_WRITE                0x00000001
+ * STGM_READWRITE            0x00000002
+ * 
+ * STGM_SHARE_DENY_NONE      0x00000040
+ * STGM_SHARE_DENY_READ      0x00000030
+ * STGM_SHARE_DENY_WRITE     0x00000020
+ * STGM_SHARE_EXCLUSIVE      0x00000010
+ * 
+ * STGM_PRIORITY             0x00040000
+ * STGM_DELETEONRELEASE      0x04000000
+ *
+ * STGM_CREATE               0x00001000
+ * STGM_CONVERT              0x00020000
+ * STGM_FAILIFTHERE          0x00000000
+ *
+ * STGM_NOSCRATCH            0x00100000
+ * STGM_NOSNAPSHOT           0x00200000
+ */
+static HRESULT validateSTGM(DWORD stgm)
+{
+  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);
+
+  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);
+
+  BOOL bSTGM_CREATE           = ((stgm & STGM_CREATE) == STGM_CREATE);
+  BOOL bSTGM_CONVERT          = ((stgm & STGM_CONVERT) == STGM_CONVERT);
+   
+  BOOL bSTGM_NOSCRATCH        = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
+  BOOL bSTGM_NOSNAPSHOT       = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
+
+  /* 
+   * 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) 
+      return E_FAIL;
+
+  /*
+   * STGM_CREATE | STGM_CONVERT
+   * if both are false, STGM_FAILIFTHERE is set to TRUE
+   */
+  if ( bSTGM_CREATE && bSTGM_CONVERT )
+    return E_FAIL;
+
+  /*
+   * STGM_NOSCRATCH requires STGM_TRANSACTED
+   */
+  if ( bSTGM_NOSCRATCH && ! bSTGM_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)) )
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+/****************************************************************************
+ *      GetShareModeFromSTGM
+ *
+ * This method will return a share mode flag from a STGM value.
+ * The STGM value is assumed valid. 
+ */
+static DWORD GetShareModeFromSTGM(DWORD stgm)
+{
+  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;
+}
+
+/****************************************************************************
+ *      GetAccessModeFromSTGM
+ *
+ * This method will return an access mode flag from a STGM value.
+ * The STGM value is assumed valid.
+ */
+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;
+}
+
+/****************************************************************************
+ *      GetCreationModeFromSTGM
+ *
+ * This method will return a creation mode flag from a STGM value.
+ * The STGM value is assumed valid.
+ */
+static DWORD GetCreationModeFromSTGM(DWORD stgm)
+{
+  if ( stgm & STGM_CREATE)
+    return CREATE_ALWAYS;
+  if (stgm & STGM_CONVERT) {
+    FIXME("STGM_CONVERT not implemented!\n");
+    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;
+}
+
+
+/*************************************************************************
+ * OLECONVERT_LoadOLE10 [Internal] 
+ *
+ * Loads the OLE10 STREAM to memory 
+ *
+ * PARAMS
+ *     pOleStream   [I] The OLESTREAM
+ *     pData        [I] Data Structure for the OLESTREAM Data
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
+ *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *     
+ *     Memory allocated for pData must be freed by the caller
+ */
+HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
+{
+	DWORD dwSize;
+	HRESULT hRes = S_OK;
+	int nTryCnt=0;
+	int max_try = 6;
+
+	pData->pData = NULL;
+	pData->pstrOleObjFileName = (CHAR *) NULL;
+
+	for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
+	{
+	/* Get the OleID */
+	dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
+	if(dwSize != sizeof(pData->dwOleID))
+	{
+		hRes = CONVERT10_E_OLESTREAM_GET;
+	}
+	else if(pData->dwOleID != OLESTREAM_ID)
+	{
+		hRes = CONVERT10_E_OLESTREAM_FMT;
+	}
+		else
+		{
+			hRes = S_OK;
+			break;
+		}
+	}
+
+	if(hRes == S_OK)
+	{
+		/* Get the TypeID...more info needed for this field */
+		dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
+		if(dwSize != sizeof(pData->dwTypeID))
+		{
+			hRes = CONVERT10_E_OLESTREAM_GET;
+		}
+	}
+	if(hRes == S_OK)
+	{
+		if(pData->dwTypeID != 0)
+		{
+			/* Get the lenght of the OleTypeName */
+			dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
+			if(dwSize != sizeof(pData->dwOleTypeNameLength))
+			{
+				hRes = CONVERT10_E_OLESTREAM_GET;
+			}
+
+			if(hRes == S_OK)
+			{
+				if(pData->dwOleTypeNameLength > 0)
+				{
+					/* Get the OleTypeName */
+					dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
+					if(dwSize != pData->dwOleTypeNameLength)
+					{
+						hRes = CONVERT10_E_OLESTREAM_GET;
+					}
+				}
+			}
+			if(bStrem1)
+			{
+				dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
+				if(dwSize != sizeof(pData->dwOleObjFileNameLength))
+				{
+					hRes = CONVERT10_E_OLESTREAM_GET;
+				}
+			if(hRes == S_OK)
+			{
+					if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
+						pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
+					pData->pstrOleObjFileName = (CHAR *)malloc(pData->dwOleObjFileNameLength);
+					if(pData->pstrOleObjFileName)
+					{
+						dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
+						if(dwSize != pData->dwOleObjFileNameLength)
+						{
+							hRes = CONVERT10_E_OLESTREAM_GET;
+						}
+					}
+					else
+						hRes = CONVERT10_E_OLESTREAM_GET;
+				}
+			}
+			else
+			{
+				/* Get the Width of the Metafile */
+				dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
+				if(dwSize != sizeof(pData->dwMetaFileWidth))
+				{
+					hRes = CONVERT10_E_OLESTREAM_GET;
+				}
+			if(hRes == S_OK)
+			{
+				/* Get the Height of the Metafile */
+				dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
+				if(dwSize != sizeof(pData->dwMetaFileHeight))
+				{
+					hRes = CONVERT10_E_OLESTREAM_GET;
+				}
+			}
+			}
+			if(hRes == S_OK)
+			{
+				/* Get the Lenght of the Data */
+				dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
+				if(dwSize != sizeof(pData->dwDataLength))
+				{
+					hRes = CONVERT10_E_OLESTREAM_GET;
+				}
+			}
+
+			if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */
+			{
+				if(!bStrem1) /* if it is a second OLE stream data */
+				{
+					pData->dwDataLength -= 8;
+					dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
+					if(dwSize != sizeof(pData->strUnknown))
+					{
+						hRes = CONVERT10_E_OLESTREAM_GET;
+					}
+				}
+			}
+			if(hRes == S_OK)
+			{
+				if(pData->dwDataLength > 0)
+				{
+					pData->pData = (BYTE *)HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
+
+					/* Get Data (ex. IStorage, Metafile, or BMP) */
+					if(pData->pData)
+					{
+						dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
+						if(dwSize != pData->dwDataLength)
+						{
+							hRes = CONVERT10_E_OLESTREAM_GET;
+						}
+					}
+					else
+					{
+						hRes = CONVERT10_E_OLESTREAM_GET;
+					}
+				}
+			}
+		}
+	}
+	return hRes;
+}
+
+/*************************************************************************
+ * OLECONVERT_SaveOLE10 [Internal] 
+ *
+ * Saves the OLE10 STREAM From memory 
+ *
+ * PARAMS
+ *     pData        [I] Data Structure for the OLESTREAM Data
+ *     pOleStream   [I] The OLESTREAM to save
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *     
+ */
+HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
+{
+    DWORD dwSize;
+    HRESULT hRes = S_OK;
+
+
+   /* Set the OleID */
+    dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
+    if(dwSize != sizeof(pData->dwOleID))
+    {
+        hRes = CONVERT10_E_OLESTREAM_PUT;
+    }
+
+    if(hRes == S_OK)
+    {
+        /* Set the TypeID */
+        dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
+        if(dwSize != sizeof(pData->dwTypeID))
+        {
+            hRes = CONVERT10_E_OLESTREAM_PUT;
+        }
+    }
+
+    if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
+    {
+        /* Set the Lenght of the OleTypeName */
+        dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
+        if(dwSize != sizeof(pData->dwOleTypeNameLength))
+        {
+            hRes = CONVERT10_E_OLESTREAM_PUT;
+        }
+
+        if(hRes == S_OK)
+        {
+            if(pData->dwOleTypeNameLength > 0)
+            {
+                /* Set the OleTypeName */
+                dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->strOleTypeName, pData->dwOleTypeNameLength);
+                if(dwSize != pData->dwOleTypeNameLength)
+                {
+                    hRes = CONVERT10_E_OLESTREAM_PUT;
+                }
+            }
+        }
+
+        if(hRes == S_OK)
+        {
+            /* Set the width of the Metafile */
+            dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
+            if(dwSize != sizeof(pData->dwMetaFileWidth))
+            {
+                hRes = CONVERT10_E_OLESTREAM_PUT;
+            }
+        }
+
+        if(hRes == S_OK)
+        {
+            /* Set the height of the Metafile */
+            dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
+            if(dwSize != sizeof(pData->dwMetaFileHeight))
+            {
+                hRes = CONVERT10_E_OLESTREAM_PUT;
+            }
+        }
+
+        if(hRes == S_OK)
+        {
+            /* Set the lenght of the Data */
+            dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
+            if(dwSize != sizeof(pData->dwDataLength))
+            {
+                hRes = CONVERT10_E_OLESTREAM_PUT;
+            }
+        }
+
+        if(hRes == S_OK)
+        {
+            if(pData->dwDataLength > 0)
+            {
+                /* Set the Data (eg. IStorage, Metafile, Bitmap) */
+                dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)  pData->pData, pData->dwDataLength);
+                if(dwSize != pData->dwDataLength)
+                {
+                    hRes = CONVERT10_E_OLESTREAM_PUT;
+                }
+            }
+        }
+    }
+    return hRes;
+}
+
+/*************************************************************************
+ * OLECONVERT_GetOLE20FromOLE10[Internal] 
+ *
+ * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
+ * opens it, and copies the content to the dest IStorage for 
+ * OleConvertOLESTREAMToIStorage
+ * 
+ *
+ * PARAMS
+ *     pDestStorage  [I] The IStorage to copy the data to
+ *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
+ *     nBufferLength [I] The size of the buffer
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     
+ *     
+ */
+void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
+{
+    HRESULT hRes;
+    HANDLE hFile;
+    IStorage *pTempStorage;
+    DWORD dwNumOfBytesWritten;
+    WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
+    WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
+
+    /* Create a temp File */
+    GetTempPathW(MAX_PATH, wstrTempDir);
+    GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
+    hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+
+    if(hFile != INVALID_HANDLE_VALUE)
+    {
+        /* Write IStorage Data to File */
+        WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
+        CloseHandle(hFile);
+
+        /* Open and copy temp storage to the Dest Storage */
+        hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
+        if(hRes == S_OK)
+        {
+            hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
+            StorageBaseImpl_Release(pTempStorage);
+        }
+        DeleteFileW(wstrTempFile);
+    }
+}
+
+
+/*************************************************************************
+ * OLECONVERT_WriteOLE20ToBuffer [Internal] 
+ *
+ * Saves the OLE10 STREAM From memory 
+ *
+ * PARAMS
+ *     pStorage  [I] The Src IStorage to copy
+ *     pData     [I] The Dest Memory to write to.
+ *
+ * RETURNS
+ *     The size in bytes allocated for pData
+ *
+ * NOTES
+ *     Memory allocated for pData must be freed by the caller
+ *
+ *     Used by OleConvertIStorageToOLESTREAM only.
+ *     
+ */
+DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
+{
+    HANDLE hFile;
+    HRESULT hRes;
+    DWORD nDataLength = 0;
+    IStorage *pTempStorage;
+    WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
+    WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
+
+    *pData = NULL;
+    
+    /* Create temp Storage */
+    GetTempPathW(MAX_PATH, wstrTempDir);
+    GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
+    hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
+
+    if(hRes == S_OK)
+    {
+        /* Copy Src Storage to the Temp Storage */
+        StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
+        StorageBaseImpl_Release(pTempStorage);
+
+        /* Open Temp Storage as a file and copy to memory */
+        hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+        if(hFile != INVALID_HANDLE_VALUE)
+        {
+            nDataLength = GetFileSize(hFile, NULL);
+            *pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,nDataLength);
+            ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
+            CloseHandle(hFile);
+        }
+        DeleteFileW(wstrTempFile);
+    }
+    return nDataLength;
+}
+
+/*************************************************************************
+ * OLECONVERT_CreateOleStream [Internal] 
+ *
+ * Creates the "\001OLE" stream in the IStorage if neccessary.
+ *
+ * PARAMS
+ *     pStorage     [I] Dest storage to create the stream in
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     This stream is still unknown, MS Word seems to have extra data
+ *     but since the data is stored in the OLESTREAM there should be
+ *     no need to recreate the stream.  If the stream is manually 
+ *     deleted it will create it with this default data.
+ *     
+ */
+void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
+    BYTE pOleStreamHeader [] = 
+    {
+        0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+        0x00, 0x00, 0x00, 0x00 
+    };
+    
+    /* Create stream if not present */
+    hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
+        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+
+    if(hRes == S_OK)
+    {
+        /* Write default Data */
+        hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
+        IStream_Release(pStream);
+    }
+}
+
+
+/*************************************************************************
+ * OLECONVERT_CreateCompObjStream [Internal] 
+ *
+ * Creates a "\001CompObj" is the destination IStorage if necessary.
+ *
+ * PARAMS
+ *     pStorage       [I] The dest IStorage to create the CompObj Stream 
+ *                        if necessary.
+ *     strOleTypeName [I] The ProgID
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     The stream data is stored in the OLESTREAM and there should be
+ *     no need to recreate the stream.  If the stream is manually 
+ *     deleted it will attempt to create it by querying the registry.
+ *
+ *     
+ */
+HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
+{
+    IStream *pStream;
+    HRESULT hStorageRes, hRes = S_OK;
+    OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
+    WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
+
+    BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
+    BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
+
+    /* Initialize the CompObj structure */
+    memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
+    memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
+    memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
+
+
+    /*  Create a CompObj stream if it doesn't exist */
+    hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName, 
+        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+    if(hStorageRes == S_OK)
+    {
+        /* copy the OleTypeName to the compobj struct */
+        IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
+        strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
+
+        /* copy the OleTypeName to the compobj struct */
+        /* Note: in the test made, these where Identical      */
+        IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
+        strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
+
+        /* Get the CLSID */
+        hRes = CLSIDFromProgID16(IStorageCompObj.strProgIDName, &(IStorageCompObj.clsid));
+
+        if(hRes == S_OK)
+        {
+            HKEY hKey;
+            LONG hErr;
+            /* Get the CLSID Default Name from the Registry */
+            hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey); 
+            if(hErr == ERROR_SUCCESS)
+            {
+                char strTemp[OLESTREAM_MAX_STR_LEN];
+                IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
+                hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength));
+                if(hErr == ERROR_SUCCESS)
+                {
+                    strcpy(IStorageCompObj.strCLSIDName, strTemp);
+                }
+                RegCloseKey(hKey);
+            }
+        }
+
+        /* Write CompObj Structure to stream */
+        hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
+
+        WriteClassStm(pStream,&(IStorageCompObj.clsid));
+
+        hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
+        if(IStorageCompObj.dwCLSIDNameLength > 0)
+        {
+            hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
+        }
+        hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
+        if(IStorageCompObj.dwOleTypeNameLength > 0)
+        {
+            hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
+        }
+        hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
+        if(IStorageCompObj.dwProgIDNameLength > 0)
+        {
+            hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
+        }
+        hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
+        IStream_Release(pStream);
+    }
+    return hRes;
+}
+
+
+/*************************************************************************
+ * OLECONVERT_CreateOlePresStream[Internal] 
+ *
+ * Creates the "\002OlePres000" Stream with the Metafile data
+ *
+ * PARAMS
+ *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
+ *     dwExtentX    [I] Width of the Metafile
+ *     dwExtentY    [I] Height of the Metafile 
+ *     pData        [I] Metafile data
+ *     dwDataLength [I] Size of the Metafile data
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *     
+ */
+void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
+    BYTE pOlePresStreamHeader [] = 
+    {
+        0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 
+        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00
+    };
+
+    BYTE pOlePresStreamHeaderEmpty [] = 
+    {
+        0x00, 0x00, 0x00, 0x00, 
+        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00
+    };
+     
+    /* Create the OlePres000 Stream */
+    hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
+        STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+
+    if(hRes == S_OK)
+    {
+        DWORD nHeaderSize;
+        OLECONVERT_ISTORAGE_OLEPRES OlePres;
+
+        memset(&OlePres, 0, sizeof(OlePres));
+        /* Do we have any metafile data to save */
+        if(dwDataLength > 0)
+        {
+            memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
+            nHeaderSize = sizeof(pOlePresStreamHeader);
+        }
+        else
+        {
+            memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
+            nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
+        }
+        /* Set width and height of the metafile */
+        OlePres.dwExtentX = dwExtentX;
+        OlePres.dwExtentY = -dwExtentY;
+
+        /* Set Data and Lenght */
+        if(dwDataLength > sizeof(METAFILEPICT16))
+        {
+            OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
+            OlePres.pData = &(pData[8]);
+        }
+        /* Save OlePres000 Data to Stream */
+        hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
+        hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
+        hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
+        hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
+        if(OlePres.dwSize > 0)
+        {
+            hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
+        }
+        IStream_Release(pStream);
+    }
+}
+
+/*************************************************************************
+ * OLECONVERT_CreateOle10NativeStream [Internal] 
+ *
+ * Creates the "\001Ole10Native" Stream (should contain a BMP)
+ *
+ * PARAMS
+ *     pStorage     [I] Dest storage to create the stream in
+ *     pData        [I] Ole10 Native Data (ex. bmp)
+ *     dwDataLength [I] Size of the Ole10 Native Data
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     Might need to verify the data and return appropriate error message
+ *     
+ */
+void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
+    
+    /* Create the Ole10Native Stream */
+    hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
+        STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+
+    if(hRes == S_OK)
+    {
+        /* Write info to stream */
+        hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
+        hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
+        IStream_Release(pStream);
+    }
+
+}
+
+/*************************************************************************
+ * OLECONVERT_GetOLE10ProgID [Internal] 
+ *
+ * Finds the ProgID (or OleTypeID) from the IStorage
+ *
+ * PARAMS
+ *     pStorage        [I] The Src IStorage to get the ProgID
+ *     strProgID       [I] the ProgID string to get
+ *     dwSize          [I] the size of the string
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *
+ *     
+ */
+HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    LARGE_INTEGER iSeekPos;
+    OLECONVERT_ISTORAGE_COMPOBJ CompObj;
+    WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
+
+    /* Open the CompObj Stream */
+    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
+        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+    if(hRes == S_OK)
+    {
+
+        /*Get the OleType from the CompObj Stream */
+        iSeekPos.s.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
+        iSeekPos.s.HighPart = 0;
+
+        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
+        IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
+        iSeekPos.s.LowPart = CompObj.dwCLSIDNameLength;
+        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
+        IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
+        iSeekPos.s.LowPart = CompObj.dwOleTypeNameLength;
+        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
+
+        IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
+        if(*dwSize > 0)
+        {
+            IStream_Read(pStream, strProgID, *dwSize, NULL);
+        }
+        IStream_Release(pStream);
+    }
+    else
+    {
+        STATSTG stat;
+        LPOLESTR wstrProgID;
+
+        /* Get the OleType from the registry */
+        REFCLSID clsid = &(stat.clsid);
+        IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
+        hRes = ProgIDFromCLSID(clsid, &wstrProgID);
+        if(hRes == S_OK)
+        {
+            *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
+        }
+ 
+    }
+    return hRes;
+}
+
+/*************************************************************************
+ * OLECONVERT_GetOle10PresData [Internal] 
+ *
+ * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
+ *
+ * PARAMS
+ *     pStorage     [I] Src IStroage
+ *     pOleStream   [I] Dest OleStream Mem Struct
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *
+ *     Memory allocated for pData must be freed by the caller
+ *      
+ *     
+ */
+void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+{
+
+    HRESULT hRes;
+    IStream *pStream;
+    WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
+
+    /* Initialize Default data for OLESTREAM */
+    pOleStreamData[0].dwOleID = OLESTREAM_ID;
+    pOleStreamData[0].dwTypeID = 2;
+    pOleStreamData[1].dwOleID = OLESTREAM_ID;
+    pOleStreamData[1].dwTypeID = 0;
+    pOleStreamData[0].dwMetaFileWidth = 0;
+    pOleStreamData[0].dwMetaFileHeight = 0;
+    pOleStreamData[0].pData = NULL;
+    pOleStreamData[1].pData = NULL;
+
+    /* Open Ole10Native Stream */
+    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
+        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+    if(hRes == S_OK)
+    {
+
+        /* Read Size and Data */
+        IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
+        if(pOleStreamData->dwDataLength > 0)
+        {
+            pOleStreamData->pData = (LPSTR) HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
+            IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
+        }
+        IStream_Release(pStream);
+    }
+
+}
+
+
+/*************************************************************************
+ * OLECONVERT_GetOle20PresData[Internal] 
+ *
+ * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
+ *
+ * PARAMS
+ *     pStorage         [I] Src IStroage
+ *     pOleStreamData   [I] Dest OleStream Mem Struct
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *     
+ *     Memory allocated for pData must be freed by the caller
+ */
+void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    OLECONVERT_ISTORAGE_OLEPRES olePress;
+    WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
+
+    /* Initialize Default data for OLESTREAM */
+    pOleStreamData[0].dwOleID = OLESTREAM_ID;
+    pOleStreamData[0].dwTypeID = 2;
+    pOleStreamData[0].dwMetaFileWidth = 0;
+    pOleStreamData[0].dwMetaFileHeight = 0;
+    pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
+    pOleStreamData[1].dwOleID = OLESTREAM_ID;
+    pOleStreamData[1].dwTypeID = 0;
+    pOleStreamData[1].dwOleTypeNameLength = 0;
+    pOleStreamData[1].strOleTypeName[0] = 0;
+    pOleStreamData[1].dwMetaFileWidth = 0;
+    pOleStreamData[1].dwMetaFileHeight = 0;
+    pOleStreamData[1].pData = NULL;
+    pOleStreamData[1].dwDataLength = 0;
+
+
+    /* Open OlePress000 stream */
+    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
+        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+    if(hRes == S_OK)
+    {
+        LARGE_INTEGER iSeekPos;
+        METAFILEPICT16 MetaFilePict;
+        char strMetafilePictName[] = "METAFILEPICT";
+
+        /* Set the TypeID for a Metafile */
+        pOleStreamData[1].dwTypeID = 5;
+
+        /* Set the OleTypeName to Metafile */
+        pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
+        strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
+
+        iSeekPos.s.HighPart = 0;
+        iSeekPos.s.LowPart = sizeof(olePress.byUnknown1);
+
+        /* Get Presentation Data */
+        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
+        IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
+        IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
+        IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
+
+        /*Set width and Height */
+        pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
+        pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
+        if(olePress.dwSize > 0)
+        {
+            /* Set Length */
+            pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
+
+            /* Set MetaFilePict struct */
+            MetaFilePict.mm = 8;
+            MetaFilePict.xExt = olePress.dwExtentX;
+            MetaFilePict.yExt = olePress.dwExtentY;
+            MetaFilePict.hMF = 0;
+
+            /* Get Metafile Data */
+            pOleStreamData[1].pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
+            memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
+            IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
+        }
+        IStream_Release(pStream);
+    }
+}
+
+/*************************************************************************
+ * OleConvertOLESTREAMToIStorage [OLE32.87] 
+ *
+ * Read info on MSDN
+ *
+ * TODO
+ *      DVTARGETDEVICE paramenter is not handled
+ *      Still unsure of some mem fields for OLE 10 Stream
+ *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
+ *      and "\001OLE" streams
+ *     
+ */
+HRESULT WINAPI OleConvertOLESTREAMToIStorage (
+    LPOLESTREAM pOleStream, 
+    LPSTORAGE pstg, 
+    const DVTARGETDEVICE* ptd)
+{
+    int i;
+    HRESULT hRes=S_OK;
+    OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
+
+    memset(pOleStreamData, 0, sizeof(pOleStreamData));
+
+    if(ptd != NULL)
+    {
+        FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
+    }
+
+    if(pstg == NULL || pOleStream == NULL)
+    {
+        hRes = E_INVALIDARG;
+    }
+
+    if(hRes == S_OK)
+    {
+        /* Load the OLESTREAM to Memory */
+        hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
+    }
+
+    if(hRes == S_OK)
+    {
+        /* Load the OLESTREAM to Memory (part 2)*/
+        hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
+    }
+
+    if(hRes == S_OK)
+    {
+
+        if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
+        {
+            /* Do we have the IStorage Data in the OLESTREAM */
+            if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
+            {
+                OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
+                OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
+            }
+            else
+            {
+                /* It must be an original OLE 1.0 source */
+                OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
+            }
+        }
+        else
+        {
+            /* It must be an original OLE 1.0 source */
+            OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
+        }
+
+        /* Create CompObj Stream if necessary */
+        hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
+        if(hRes == S_OK)
+        {
+            /*Create the Ole Stream if necessary */
+            OLECONVERT_CreateOleStream(pstg);
+        }
+    }
+
+
+    /* Free allocated memory */
+    for(i=0; i < 2; i++)
+    {
+        if(pOleStreamData[i].pData != NULL)
+        {
+            HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
+        }
+        if(pOleStreamData[i].pstrOleObjFileName != NULL)
+	{
+        	HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
+        	pOleStreamData[i].pstrOleObjFileName = NULL;
+	}
+    }
+    return hRes;
+}
+
+/*************************************************************************
+ * OleConvertIStorageToOLESTREAM [OLE32.85]
+ *
+ * Read info on MSDN
+ *
+ * Read info on MSDN
+ *
+ * TODO
+ *      Still unsure of some mem fields for OLE 10 Stream
+ *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
+ *      and "\001OLE" streams.
+ *     
+ */
+HRESULT WINAPI OleConvertIStorageToOLESTREAM (
+    LPSTORAGE pstg, 
+    LPOLESTREAM pOleStream)
+{
+    int i;
+    HRESULT hRes = S_OK;
+    IStream *pStream;
+    OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
+    WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
+
+
+    memset(pOleStreamData, 0, sizeof(pOleStreamData));
+
+    if(pstg == NULL || pOleStream == NULL)
+    {
+        hRes = E_INVALIDARG;
+    }
+    if(hRes == S_OK)
+    {
+        /* Get the ProgID */
+        pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
+        hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
+    }
+    if(hRes == S_OK)
+    {
+        /*Was it originaly Ole10 */
+        hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);    
+        if(hRes == S_OK)
+        {
+            IStream_Release(pStream);
+            /*Get Presentation Data for Ole10Native */
+            OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
+        }
+        else
+        {
+            /*Get Presentation Data (OLE20)*/
+            OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
+        }
+
+        /* Save OLESTREAM */
+        hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
+        if(hRes == S_OK)
+        {
+            hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
+        }
+
+    }
+
+    /* Free allocated memory */
+    for(i=0; i < 2; i++)
+    {
+        if(pOleStreamData[i].pData != NULL)
+        {
+            HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
+        }
+    }
+
+    return hRes;
+}
+
+#ifdef __WIN32OS2__
+/******************************************************************************
+ * StgIsStorageFile16 [STORAGE.5]
+ */
+HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
+static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
+        HFILE           hf;
+        OFSTRUCT        ofs;
+        BYTE            magic[24];
+
+        TRACE_(ole)("(\'%s\')\n",fn);
+        hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
+        if (hf==HFILE_ERROR)
+                return STG_E_FILENOTFOUND;
+        if (24!=_lread(hf,magic,24)) {
+                WARN_(ole)(" too short\n");
+                _lclose(hf);
+                return S_FALSE;
+        }
+        if (!memcmp(magic,STORAGE_magic,8)) {
+                WARN_(ole)(" -> YES\n");
+                _lclose(hf);
+                return S_OK;
+        }
+        if (!memcmp(magic,STORAGE_notmagic,8)) {
+                WARN_(ole)(" -> NO\n");
+                _lclose(hf);
+                return S_FALSE;
+        }
+        if (!memcmp(magic,STORAGE_oldmagic,8)) {
+                WARN_(ole)(" -> old format\n");
+                _lclose(hf);
+                return STG_E_OLDFORMAT;
+        }
+        WARN_(ole)(" -> Invalid header.\n");
+        _lclose(hf);
+        return STG_E_INVALIDHEADER;
+}
+
+HRESULT WINAPI
+StgIsStorageFile(LPCOLESTR fn)
+{
+        LPOLESTR16      xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
+        HRESULT       ret = StgIsStorageFile16(xfn);
+
+        HeapFree(GetProcessHeap(),0,xfn);
+        return ret;
+}
+#endif
Index: trunk/src/ole32/storage32.h
===================================================================
--- trunk/src/ole32/storage32.h	(revision 5026)
+++ trunk/src/ole32/storage32.h	(revision 5026)
@@ -0,0 +1,875 @@
+/*
+ * Compound Storage (32 bit version)
+ *
+ * Implemented using the documentation of the LAOLA project at
+ * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
+ * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
+ *
+ * This include file contains definitions of types and function
+ * prototypes that are used in the many files implementing the 
+ * storage functionality
+ *
+ * Copyright 1998,1999 Francis Beaudet
+ * Copyright 1998,1999 Thuy Nguyen
+ */
+#ifndef __STORAGE32_H__
+#define __STORAGE32_H__
+
+#include "wtypes.h"
+#include "winnt.h"
+#include "wine/obj_base.h"
+#include "wine/obj_storage.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Definitions for the file format offsets.
+ */
+static const ULONG OFFSET_BIGBLOCKSIZEBITS   = 0x0000001e;
+static const ULONG OFFSET_SMALLBLOCKSIZEBITS = 0x00000020;
+static const ULONG OFFSET_BBDEPOTCOUNT	     = 0x0000002C;
+static const ULONG OFFSET_ROOTSTARTBLOCK     = 0x00000030;
+static const ULONG OFFSET_SBDEPOTSTART	     = 0x0000003C;
+static const ULONG OFFSET_EXTBBDEPOTSTART    = 0x00000044;
+static const ULONG OFFSET_EXTBBDEPOTCOUNT    = 0x00000048;
+static const ULONG OFFSET_BBDEPOTSTART	     = 0x0000004C;
+static const ULONG OFFSET_PS_NAME            = 0x00000000;
+static const ULONG OFFSET_PS_NAMELENGTH	     = 0x00000040;
+static const ULONG OFFSET_PS_PROPERTYTYPE    = 0x00000042;
+static const ULONG OFFSET_PS_PREVIOUSPROP    = 0x00000044;
+static const ULONG OFFSET_PS_NEXTPROP        = 0x00000048;   
+static const ULONG OFFSET_PS_DIRPROP	     = 0x0000004C;
+static const ULONG OFFSET_PS_GUID            = 0x00000050;
+static const ULONG OFFSET_PS_TSS1	     = 0x00000064;
+static const ULONG OFFSET_PS_TSD1            = 0x00000068;
+static const ULONG OFFSET_PS_TSS2            = 0x0000006C;
+static const ULONG OFFSET_PS_TSD2            = 0x00000070;
+static const ULONG OFFSET_PS_STARTBLOCK	     = 0x00000074; 
+static const ULONG OFFSET_PS_SIZE	     = 0x00000078; 
+static const WORD  DEF_BIG_BLOCK_SIZE_BITS   = 0x0009;
+static const WORD  DEF_SMALL_BLOCK_SIZE_BITS = 0x0006;
+static const WORD  DEF_BIG_BLOCK_SIZE        = 0x0200;
+static const WORD  DEF_SMALL_BLOCK_SIZE      = 0x0040;
+static const ULONG BLOCK_EXTBBDEPOT          = 0xFFFFFFFC;
+static const ULONG BLOCK_SPECIAL             = 0xFFFFFFFD;
+static const ULONG BLOCK_END_OF_CHAIN        = 0xFFFFFFFE;
+static const ULONG BLOCK_UNUSED              = 0xFFFFFFFF;
+static const ULONG PROPERTY_NULL             = 0xFFFFFFFF;
+
+#define PROPERTY_NAME_MAX_LEN    0x20
+#define PROPERTY_NAME_BUFFER_LEN 0x40             
+
+#define PROPSET_BLOCK_SIZE 0x00000080
+
+/*
+ * Property type of relation
+ */
+#define PROPERTY_RELATION_PREVIOUS 0
+#define PROPERTY_RELATION_NEXT     1
+#define PROPERTY_RELATION_DIR      2
+
+/*
+ * Property type constants
+ */
+#define PROPTYPE_STORAGE 0x01
+#define PROPTYPE_STREAM  0x02
+#define PROPTYPE_ROOT    0x05
+
+/*
+ * These defines assume a hardcoded blocksize. The code will assert
+ * if the blocksize is different. Some changes will have to be done if it
+ * becomes the case.
+ */
+#define BIG_BLOCK_SIZE           0x200
+#define COUNT_BBDEPOTINHEADER    109
+#define LIMIT_TO_USE_SMALL_BLOCK 0x1000
+#define NUM_BLOCKS_PER_DEPOT_BLOCK 128
+
+/*
+ * 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};
+
+/*
+ * Forward declarations of all the structures used by the storage
+ * module.
+ */
+typedef struct StorageBaseImpl     StorageBaseImpl;
+typedef struct StorageImpl         StorageImpl;
+typedef struct StorageInternalImpl StorageInternalImpl;
+typedef struct BlockChainStream      BlockChainStream;
+typedef struct SmallBlockChainStream SmallBlockChainStream;
+typedef struct IEnumSTATSTGImpl      IEnumSTATSTGImpl;
+typedef struct StgProperty           StgProperty;
+typedef struct StgStreamImpl         StgStreamImpl;
+
+/*
+ * This utility structure is used to read/write the information in a storage
+ * property.
+ */
+struct StgProperty
+{
+  WCHAR	         name[PROPERTY_NAME_MAX_LEN];
+  WORD	         sizeOfNameString;
+  BYTE	         propertyType;
+  ULONG	         previousProperty;
+  ULONG	         nextProperty;
+  ULONG          dirProperty;
+  GUID           propertyUniqueID;
+  ULONG          timeStampS1;
+  ULONG          timeStampD1;
+  ULONG          timeStampS2;
+  ULONG          timeStampD2;
+  ULONG          startingBlock;
+  ULARGE_INTEGER size;
+};
+
+/*************************************************************************
+ * Big Block File support
+ *
+ * The big block file is an abstraction of a flat file separated in
+ * same sized blocks. The implementation for the methods described in 
+ * this section appear in stg_bigblockfile.c
+ */
+
+/*
+ * Declaration of the data structures
+ */
+typedef struct BigBlockFile BigBlockFile,*LPBIGBLOCKFILE;
+typedef struct MappedPage   MappedPage,*LPMAPPEDPAGE;
+
+struct BigBlockFile
+{
+  BOOL fileBased;
+  ULARGE_INTEGER filesize;
+  ULONG blocksize;
+  HANDLE hfile;
+  HANDLE hfilemap;
+  DWORD flProtect;
+  MappedPage *maplist;
+  MappedPage *victimhead, *victimtail;
+  ULONG num_victim_pages;
+  ILockBytes *pLkbyt;
+  HGLOBAL hbytearray;
+  LPVOID pbytearray;
+};
+
+/*
+ * Declaration of the functions used to manipulate the BigBlockFile
+ * data structure.
+ */
+BigBlockFile*  BIGBLOCKFILE_Construct(HANDLE hFile,
+                                      ILockBytes* pLkByt,
+                                      DWORD openFlags,
+                                      ULONG blocksize,
+                                      BOOL fileBased);
+void           BIGBLOCKFILE_Destructor(LPBIGBLOCKFILE This);
+void*          BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index);
+void*          BIGBLOCKFILE_GetROBigBlock(LPBIGBLOCKFILE This, ULONG index);
+void           BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock);
+void           BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize);
+ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This);
+
+/*************************************************************************
+ * Ole Convert support
+ */
+
+void OLECONVERT_CreateOleStream(LPSTORAGE pStorage);
+HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName);
+
+/****************************************************************************
+ * Storage32BaseImpl definitions.
+ *
+ * This stucture defines the base information contained in all implementations
+ * of IStorage32 contained in this filee storage implementation.
+ *
+ * In OOP terms, this is the base class for all the IStorage32 implementations
+ * contained in this file.
+ */
+struct StorageBaseImpl
+{
+  ICOM_VFIELD(IStorage);   /* Needs to be the first item in the stuct
+			    * since we want to cast this in a Storage32 pointer */
+
+  /*
+   * Reference count of this object
+   */
+  ULONG ref;
+  
+  /* 
+   * Ancestor storage (top level) 
+   */
+  StorageImpl* ancestorStorage;		 
+  
+  /*
+   * Index of the property for the root of
+   * this storage
+   */
+  ULONG rootPropertySetIndex;
+  
+  /* 
+   * virtual Destructor method.
+   */
+  void (*v_destructor)(StorageBaseImpl*);
+};
+
+
+/*
+ * Prototypes for the methods of the Storage32BaseImpl class.
+ */
+HRESULT WINAPI StorageBaseImpl_QueryInterface(
+            IStorage*        iface,
+            REFIID             riid,
+            void**             ppvObject);
+        
+ULONG WINAPI StorageBaseImpl_AddRef( 
+            IStorage*        iface);
+        
+ULONG WINAPI StorageBaseImpl_Release( 
+            IStorage*        iface);
+        
+HRESULT WINAPI StorageBaseImpl_OpenStream( 
+            IStorage*        iface,
+            const OLECHAR*   pwcsName,  /* [string][in] */
+            void*              reserved1, /* [unique][in] */
+            DWORD              grfMode,   /* [in] */        
+            DWORD              reserved2, /* [in] */        
+            IStream**        ppstm);    /* [out] */   
+    
+HRESULT WINAPI StorageBaseImpl_OpenStorage( 
+            IStorage*        iface,
+            const OLECHAR*   pwcsName,      /* [string][unique][in] */ 
+            IStorage*        pstgPriority,  /* [unique][in] */         
+            DWORD              grfMode,       /* [in] */                 
+            SNB              snbExclude,    /* [unique][in] */         
+            DWORD              reserved,      /* [in] */                 
+            IStorage**       ppstg);        /* [out] */                
+          
+HRESULT WINAPI StorageBaseImpl_EnumElements( 
+            IStorage*        iface,
+            DWORD              reserved1, /* [in] */                  
+            void*              reserved2, /* [size_is][unique][in] */ 
+            DWORD              reserved3, /* [in] */                  
+            IEnumSTATSTG**     ppenum);   /* [out] */   
+
+HRESULT WINAPI StorageBaseImpl_Stat( 
+            IStorage*        iface,
+            STATSTG*           pstatstg,     /* [out] */ 
+            DWORD              grfStatFlag); /* [in] */  
+
+HRESULT WINAPI StorageBaseImpl_RenameElement(
+            IStorage*        iface,
+            const OLECHAR*   pwcsOldName,  /* [string][in] */
+            const OLECHAR*   pwcsNewName); /* [string][in] */
+
+HRESULT WINAPI StorageBaseImpl_CreateStream(
+            IStorage*        iface,
+            const OLECHAR*   pwcsName,  /* [string][in] */
+            DWORD              grfMode,   /* [in] */
+            DWORD              reserved1, /* [in] */
+            DWORD              reserved2, /* [in] */
+            IStream**        ppstm);    /* [out] */
+
+HRESULT WINAPI StorageBaseImpl_SetClass(
+            IStorage*        iface,
+            REFCLSID           clsid);  /* [in] */
+
+/****************************************************************************
+ * Storage32Impl definitions.
+ *
+ * This implementation of the IStorage32 interface represents a root
+ * storage. Basically, a document file.
+ */
+struct StorageImpl
+{
+  ICOM_VFIELD(IStorage);   /* Needs to be the first item in the stuct
+				      * since we want to cast this in a Storage32 pointer */
+
+  /*
+   * Declare the member of the Storage32BaseImpl class to allow
+   * casting as a Storage32BaseImpl
+   */
+  ULONG		        ref;
+  struct StorageImpl* ancestorStorage;		 
+  ULONG                 rootPropertySetIndex;
+  void (*v_destructor)(struct StorageImpl*);
+  
+  /*
+   * The following data members are specific to the Storage32Impl
+   * class
+   */
+  HANDLE           hFile;      /* Physical support for the Docfile */
+  
+  /*
+   * File header
+   */
+  WORD  bigBlockSizeBits;
+  WORD  smallBlockSizeBits;
+  ULONG bigBlockSize;
+  ULONG smallBlockSize;
+  ULONG bigBlockDepotCount;
+  ULONG rootStartBlock;
+  ULONG smallBlockDepotStart;
+  ULONG extBigBlockDepotStart;
+  ULONG extBigBlockDepotCount;
+  ULONG bigBlockDepotStart[COUNT_BBDEPOTINHEADER];
+
+  ULONG blockDepotCached[NUM_BLOCKS_PER_DEPOT_BLOCK];
+  ULONG indexBlockDepotCached;
+  ULONG prevFreeBlock;
+
+  /*
+   * Abstraction of the big block chains for the chains of the header.
+   */
+  BlockChainStream* rootBlockChain;
+  BlockChainStream* smallBlockDepotChain;
+  BlockChainStream* smallBlockRootChain;  
+
+  /*
+   * Pointer to the big block file abstraction
+   */
+  BigBlockFile* bigBlockFile; 
+};
+
+/*
+ * Method declaration for the Storage32Impl class
+ */        
+
+HRESULT WINAPI StorageImpl_CreateStorage( 
+            IStorage*      iface,
+            const OLECHAR* pwcsName,  /* [string][in] */ 
+            DWORD            grfMode,   /* [in] */ 
+            DWORD            dwStgFmt,  /* [in] */ 
+            DWORD            reserved2, /* [in] */ 
+            IStorage**     ppstg);    /* [out] */ 
+        
+HRESULT WINAPI StorageImpl_CopyTo( 
+            IStorage*      iface,
+            DWORD          ciidExclude,  /* [in] */ 
+            const IID*     rgiidExclude, /* [size_is][unique][in] */ 
+            SNB            snbExclude, /* [unique][in] */ 
+            IStorage*    pstgDest);    /* [unique][in] */ 
+        
+HRESULT WINAPI StorageImpl_MoveElementTo( 
+            IStorage*      iface,
+            const OLECHAR* pwcsName,    /* [string][in] */ 
+            IStorage*      pstgDest,    /* [unique][in] */ 
+            const OLECHAR* pwcsNewName, /* [string][in] */ 
+            DWORD            grfFlags);   /* [in] */ 
+        
+HRESULT WINAPI StorageImpl_Commit( 
+            IStorage*      iface,
+            DWORD          grfCommitFlags); /* [in] */ 
+        
+HRESULT WINAPI StorageImpl_Revert( 
+            IStorage*      iface);
+        
+HRESULT WINAPI StorageImpl_DestroyElement( 
+            IStorage*      iface,
+            const OLECHAR* pwcsName); /* [string][in] */ 
+        
+HRESULT WINAPI StorageImpl_SetElementTimes( 
+            IStorage*      iface,
+            const OLECHAR* pwcsName, /* [string][in] */ 
+            const FILETIME*  pctime,   /* [in] */ 
+            const FILETIME*  patime,   /* [in] */ 
+            const FILETIME*  pmtime);  /* [in] */ 
+
+HRESULT WINAPI StorageImpl_SetStateBits( 
+            IStorage*      iface,
+            DWORD          grfStateBits, /* [in] */ 
+            DWORD          grfMask);     /* [in] */ 
+        
+void StorageImpl_Destroy(
+	    StorageImpl* This);
+
+HRESULT StorageImpl_Construct(
+            StorageImpl* This,
+            HANDLE       hFile,
+            ILockBytes*  pLkbyt,
+            DWORD        openFlags,
+            BOOL         fileBased,
+            BOOL         fileCreate);
+
+BOOL StorageImpl_ReadBigBlock(
+            StorageImpl* This,
+	    ULONG          blockIndex,
+	    void*          buffer);
+
+BOOL StorageImpl_WriteBigBlock(
+            StorageImpl* This,
+	    ULONG          blockIndex,
+	    void*          buffer);
+
+void* StorageImpl_GetROBigBlock(
+            StorageImpl* This,
+	    ULONG          blockIndex);
+
+void* StorageImpl_GetBigBlock(
+	    StorageImpl* This,
+	    ULONG          blockIndex);
+
+void StorageImpl_ReleaseBigBlock(
+            StorageImpl* This,
+            void*          pBigBlock);
+
+ULONG StorageImpl_GetNextFreeBigBlock(
+            StorageImpl* This);
+
+void StorageImpl_FreeBigBlock(
+            StorageImpl* This,
+	    ULONG blockIndex);
+
+ULONG StorageImpl_GetNextBlockInChain(
+            StorageImpl* This,
+	    ULONG blockIndex);
+
+void StorageImpl_SetNextBlockInChain(
+            StorageImpl* This,
+	    ULONG blockIndex,
+      ULONG nextBlock);
+
+HRESULT StorageImpl_LoadFileHeader(
+	    StorageImpl* This);
+
+void StorageImpl_SaveFileHeader(
+            StorageImpl* This);
+
+BOOL StorageImpl_ReadProperty(
+            StorageImpl* This,
+	    ULONG          index,
+	    StgProperty*    buffer);
+
+BOOL StorageImpl_WriteProperty(
+            StorageImpl* This,
+	    ULONG          index,
+	    StgProperty*   buffer);
+
+BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
+                      StorageImpl* This,
+                      SmallBlockChainStream** ppsbChain);
+
+ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This,
+                                         ULONG blockIndex);
+
+void Storage32Impl_AddBlockDepot(StorageImpl* This,
+                                 ULONG blockIndex);
+
+ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This);
+
+ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This,
+                                     ULONG depotIndex);
+
+void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
+                                    ULONG depotIndex,
+                                    ULONG blockIndex);
+/****************************************************************************
+ * 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
+{
+  ICOM_VFIELD(IStorage);	/* Needs to be the first item in the stuct
+				 * since we want to cast this in a Storage32 pointer */
+
+  /*
+   * Declare the member of the Storage32BaseImpl class to allow
+   * casting as a Storage32BaseImpl
+   */
+  ULONG		             ref;
+  struct StorageImpl* ancestorStorage;		 
+  ULONG                    rootPropertySetIndex;
+  void (*v_destructor)(struct StorageInternalImpl*);
+
+  /*
+   * There is no specific data for this class.
+   */
+};
+
+/*
+ * Method definitions for the Storage32InternalImpl class.
+ */
+StorageInternalImpl* StorageInternalImpl_Construct(
+	    StorageImpl* ancestorStorage,	
+	    ULONG          rootTropertyIndex);
+
+void StorageInternalImpl_Destroy(
+       	    StorageInternalImpl* This);
+
+HRESULT WINAPI StorageInternalImpl_Commit( 
+	    IStorage*            iface,
+	    DWORD                  grfCommitFlags); /* [in] */ 
+
+HRESULT WINAPI StorageInternalImpl_Revert( 
+     	    IStorage*            iface);
+
+
+/****************************************************************************
+ * 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.
+ */
+struct IEnumSTATSTGImpl
+{
+  ICOM_VFIELD(IEnumSTATSTG);    /* Needs to be the first item in the stuct
+					 * since we want to cast this in a IEnumSTATSTG pointer */
+  
+  ULONG		 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
+};
+
+/*
+ * Method definitions for the IEnumSTATSTGImpl class.
+ */
+HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
+	    IEnumSTATSTG*     iface,
+	    REFIID            riid,
+	    void**            ppvObject);
+        
+ULONG WINAPI IEnumSTATSTGImpl_AddRef(
+            IEnumSTATSTG*     iface); 
+        
+ULONG WINAPI IEnumSTATSTGImpl_Release(
+            IEnumSTATSTG*     iface);
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Next(
+            IEnumSTATSTG*     iface,
+	    ULONG             celt,
+	    STATSTG*          rgelt,
+	    ULONG*            pceltFetched);
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Skip(
+            IEnumSTATSTG*     iface,
+	    ULONG             celt);
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Reset(
+            IEnumSTATSTG* iface);
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Clone(
+            IEnumSTATSTG*     iface,
+	    IEnumSTATSTG**    ppenum);
+
+IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
+            StorageImpl* This,
+	    ULONG          firstPropertyNode);
+
+void IEnumSTATSTGImpl_Destroy(
+            IEnumSTATSTGImpl* This);
+
+void IEnumSTATSTGImpl_PushSearchNode(
+	    IEnumSTATSTGImpl* This,
+	    ULONG             nodeToPush);
+
+ULONG IEnumSTATSTGImpl_PopSearchNode(
+            IEnumSTATSTGImpl* This,
+	    BOOL            remove);
+
+ULONG IEnumSTATSTGImpl_FindProperty(
+            IEnumSTATSTGImpl* This,
+	    const OLECHAR*  lpszPropName,
+	    StgProperty*      buffer);
+
+INT IEnumSTATSTGImpl_FindParentProperty(
+  IEnumSTATSTGImpl *This,
+  ULONG             childProperty,
+  StgProperty      *currentProperty,
+  ULONG            *propertyId);
+
+
+/****************************************************************************
+ * StgStreamImpl definitions.
+ *
+ * This class imlements the IStream32 inteface and represents a stream
+ * located inside a storage object.
+ */
+struct StgStreamImpl
+{
+  ICOM_VFIELD(IStream);  /* Needs to be the first item in the stuct
+				    * since we want to cast this in a IStream pointer */
+  
+  /*
+   * Reference count
+   */
+  ULONG		     ref;
+
+  /*
+   * Storage that is the parent(owner) of the stream
+   */
+  StorageBaseImpl* parentStorage;
+
+  /*
+   * Access mode of this stream.
+   */
+  DWORD grfMode;
+
+  /*
+   * Index of the property that owns (points to) this stream.
+   */
+  ULONG              ownerProperty;
+
+  /*
+   * Helper variable that contains the size of the stream
+   */
+  ULARGE_INTEGER     streamSize;
+
+  /*
+   * This is the current position of the cursor in the stream
+   */
+  ULARGE_INTEGER     currentPosition;
+  
+  /*
+   * The information in the stream is represented by a chain of small blocks
+   * or a chain of large blocks. Depending on the case, one of the two
+   * following variabled points to that information.
+   */
+  BlockChainStream*      bigBlockChain;
+  SmallBlockChainStream* smallBlockChain;
+};
+
+/*
+ * Method definition for the StgStreamImpl class.
+ */
+StgStreamImpl* StgStreamImpl_Construct(
+		StorageBaseImpl* parentStorage,
+    DWORD            grfMode,
+    ULONG            ownerProperty);
+
+void StgStreamImpl_Destroy(
+                StgStreamImpl* This);
+
+void StgStreamImpl_OpenBlockChain(
+                StgStreamImpl* This);
+
+HRESULT WINAPI StgStreamImpl_QueryInterface(
+		IStream*      iface,
+		REFIID         riid,		/* [in] */          
+		void**         ppvObject);  /* [iid_is][out] */ 
+        
+ULONG WINAPI StgStreamImpl_AddRef(
+		IStream*      iface);
+        
+ULONG WINAPI StgStreamImpl_Release(
+		IStream*      iface);
+        
+HRESULT WINAPI StgStreamImpl_Read( 
+	        IStream*      iface,
+		void*          pv,        /* [length_is][size_is][out] */
+		ULONG          cb,        /* [in] */                     
+		ULONG*         pcbRead);  /* [out] */                    
+        
+HRESULT WINAPI StgStreamImpl_Write(
+		IStream*      iface,
+		const void*    pv,          /* [size_is][in] */ 
+		ULONG          cb,          /* [in] */          
+		ULONG*         pcbWritten); /* [out] */         
+        
+HRESULT WINAPI StgStreamImpl_Seek( 
+		IStream*      iface,
+		LARGE_INTEGER   dlibMove,         /* [in] */ 
+		DWORD           dwOrigin,         /* [in] */ 
+		ULARGE_INTEGER* plibNewPosition); /* [out] */
+        
+HRESULT WINAPI StgStreamImpl_SetSize( 
+	        IStream*      iface,
+		ULARGE_INTEGER  libNewSize);  /* [in] */ 
+        
+HRESULT WINAPI StgStreamImpl_CopyTo( 
+		IStream*      iface,
+		IStream*      pstm,         /* [unique][in] */ 
+		ULARGE_INTEGER  cb,           /* [in] */         
+		ULARGE_INTEGER* pcbRead,      /* [out] */        
+		ULARGE_INTEGER* pcbWritten);  /* [out] */        
+
+HRESULT WINAPI StgStreamImpl_Commit( 
+	    	IStream*      iface,
+		DWORD           grfCommitFlags); /* [in] */ 
+        
+HRESULT WINAPI StgStreamImpl_Revert( 
+		IStream*  iface);
+        
+HRESULT WINAPI StgStreamImpl_LockRegion( 
+		IStream*     iface,
+		ULARGE_INTEGER libOffset,   /* [in] */ 
+		ULARGE_INTEGER cb,          /* [in] */ 
+		DWORD          dwLockType); /* [in] */ 
+        
+HRESULT WINAPI StgStreamImpl_UnlockRegion( 
+		IStream*     iface,
+		ULARGE_INTEGER libOffset,   /* [in] */ 
+	        ULARGE_INTEGER cb,          /* [in] */ 
+		DWORD          dwLockType); /* [in] */ 
+        
+HRESULT WINAPI StgStreamImpl_Stat( 
+		IStream*     iface,
+	        STATSTG*       pstatstg,     /* [out] */
+	        DWORD          grfStatFlag); /* [in] */ 
+        
+HRESULT WINAPI StgStreamImpl_Clone( 
+		IStream*     iface,
+		IStream**    ppstm);       /* [out] */ 
+
+
+/********************************************************************************
+ * The StorageUtl_ functions are miscelaneous utility functions. Most of which are
+ * abstractions used to read values from file buffers without having to worry 
+ * about bit order
+ */
+void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value);
+void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value);
+void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value);
+void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value);
+void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value);
+void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value);
+void StorageUtl_CopyPropertyToSTATSTG(STATSTG*     destination,
+					     StgProperty* source,
+					     int          statFlags);
+
+/****************************************************************************
+ * BlockChainStream definitions.
+ *
+ * The BlockChainStream class is a utility class that is used to create an
+ * abstraction of the big block chains in the storage file.
+ */
+struct BlockChainStream
+{
+  StorageImpl* parentStorage;
+  ULONG*       headOfStreamPlaceHolder;
+  ULONG        ownerPropertyIndex;
+  ULONG        lastBlockNoInSequence;
+  ULONG        lastBlockNoInSequenceIndex;
+  ULONG        tailIndex;
+  ULONG        numBlocks;
+};
+
+/*
+ * Methods for the BlockChainStream class.
+ */
+BlockChainStream* BlockChainStream_Construct(
+		StorageImpl* parentStorage,	
+		ULONG*         headOfStreamPlaceHolder,
+		ULONG          propertyIndex);
+
+void BlockChainStream_Destroy(
+		BlockChainStream* This);
+
+ULONG BlockChainStream_GetHeadOfChain(
+		BlockChainStream* This);
+
+BOOL BlockChainStream_ReadAt(
+		BlockChainStream* This,
+		ULARGE_INTEGER offset,
+		ULONG          size,
+		void*          buffer,
+		ULONG*         bytesRead);
+
+BOOL BlockChainStream_WriteAt(
+		BlockChainStream* This,
+		ULARGE_INTEGER offset,
+		ULONG          size,
+		const void*    buffer,
+		ULONG*         bytesWritten);
+
+BOOL BlockChainStream_SetSize(
+		BlockChainStream* This,
+		ULARGE_INTEGER    newSize);
+
+ULARGE_INTEGER BlockChainStream_GetSize(
+    BlockChainStream* This);
+
+ULONG BlockChainStream_GetCount(
+    BlockChainStream* This);
+
+/****************************************************************************
+ * SmallBlockChainStream definitions.
+ *
+ * The SmallBlockChainStream class is a utility class that is used to create an
+ * abstraction of the small block chains in the storage file.
+ */
+struct SmallBlockChainStream
+{
+  StorageImpl* parentStorage;
+  ULONG          ownerPropertyIndex;
+};
+
+/*
+ * Methods of the SmallBlockChainStream class.
+ */
+SmallBlockChainStream* SmallBlockChainStream_Construct(
+	       StorageImpl* parentStorage,	
+	       ULONG          propertyIndex);
+
+void SmallBlockChainStream_Destroy(
+	       SmallBlockChainStream* This);
+
+ULONG SmallBlockChainStream_GetHeadOfChain(
+	       SmallBlockChainStream* This);
+
+ULONG SmallBlockChainStream_GetNextBlockInChain(
+	       SmallBlockChainStream* This,
+	       ULONG                  blockIndex);
+
+void SmallBlockChainStream_SetNextBlockInChain(
+         SmallBlockChainStream* This,
+         ULONG                  blockIndex,
+         ULONG                  nextBlock);
+
+void SmallBlockChainStream_FreeBlock(
+         SmallBlockChainStream* This,
+         ULONG                  blockIndex);
+
+ULONG SmallBlockChainStream_GetNextFreeBlock(
+         SmallBlockChainStream* This);
+
+BOOL SmallBlockChainStream_ReadAt(
+	       SmallBlockChainStream* This,
+	       ULARGE_INTEGER offset,
+	       ULONG          size,
+	       void*          buffer,
+	       ULONG*         bytesRead);
+
+BOOL SmallBlockChainStream_WriteAt(
+	       SmallBlockChainStream* This,
+	       ULARGE_INTEGER offset,
+	       ULONG          size,
+	       const void*    buffer,
+	       ULONG*         bytesWritten);
+
+BOOL SmallBlockChainStream_SetSize(
+	       SmallBlockChainStream* This,
+	       ULARGE_INTEGER          newSize);
+
+ULARGE_INTEGER SmallBlockChainStream_GetSize(
+         SmallBlockChainStream* This);
+
+ULONG SmallBlockChainStream_GetCount(
+         SmallBlockChainStream* This);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STORAGE32_H__ */
+
+
+
