Alternative implementation of DocFiles (long, posted for archival purposes)

Troy Rollo wine at troy.rollo.name
Thu Feb 5 20:24:06 CST 2004


The attached file contains the CorVu implementation of DocFiles (the Microsoft 
compound file format). This was coded from scratch based on analysis of the 
file format some time in or before 1998. There was no reliance on the LAOLA 
project, and there are several aspects of the DocFile format that are 
implemented in this code (and documented in docfile.h) that are not 
documented by the LAOLA project and not implemented in Wine.

Because it's in C++, it's not directly usable in Wine, but it may be of use to 
anybody seeking to improve the Wine implementation of DocFiles in the future.

The code is being released under the LGPL.
-------------- next part --------------
Files no-docfile/.docfile.h.swp and docfile/.docfile.h.swp differ
diff -uN no-docfile/Makefile docfile/Makefile
--- no-docfile/Makefile	1970-01-01 10:00:00.000000000 +1000
+++ docfile/Makefile	2004-02-05 09:07:05.000000000 +1100
@@ -0,0 +1,19 @@
+.SUFFIXES: .a .o .s .i .d .c .cpp
+
+CC=gcc
+
+#DEFS=-DDF_INTEL_BYTE_ORDER
+
+.cpp.o:
+	$(CC) $(DEFS) -g -x c++ -c $*.cpp
+
+.c.o:
+	$(CC) $(DEFS) -g -c $*.c
+
+DFOBJECTS=docfile.o dfint.o oleinit.o dfrc.o flokbyte.o \
+	dfmgr.o dfo.o dfstg.o dfess.o dfstream.o redblack.o guid.o
+
+default: $(DFOBJECTS)
+	-rm libdf.a
+	ar q libdf.a $(DFOBJECTS)
+	-ranlib libdf.a
diff -uN no-docfile/dfconv.h docfile/dfconv.h
--- no-docfile/dfconv.h	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dfconv.h	2004-02-05 09:00:29.000000000 +1100
@@ -0,0 +1,109 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __DFCONV_H
+#define __DFCONV_H
+
+#ifdef DF_INTEL_BYTE_ORDER
+#define SI4(x) x
+#define SI2(x) x
+#else
+#define SI4(x) __CV_SI4::__CV_SI4(x)
+#define SI2(x) __CV_SI2::__CV_SI2(x)
+
+class	__CV_SI4
+{
+private:
+	df_int4 &iValue;
+
+public:
+	inline
+	__CV_SI4(df_int4 &iValue_) :
+		iValue(iValue_)
+	{
+	}
+
+	inline	df_int4
+	operator=(df_int4 iValue_)
+	{
+		char	*pchSource = (char *) &iValue_;
+		char	*pchDest = (char *) &iValue;
+
+		pchDest[0] = pchSource[3];
+		pchDest[1] = pchSource[2];
+		pchDest[2] = pchSource[1];
+		pchDest[3] = pchSource[0];
+		return iValue_;
+	}
+
+	inline
+	operator df_int4(void) const
+	{
+		df_int4 iValue_;
+
+		char	*pchSource = (char *) &iValue;
+		char	*pchDest = (char *) &iValue_;
+
+		pchDest[0] = pchSource[3];
+		pchDest[1] = pchSource[2];
+		pchDest[2] = pchSource[1];
+		pchDest[3] = pchSource[0];
+		return iValue_;
+	}
+};
+
+class	__CV_SI2
+{
+private:
+	df_int2 &iValue;
+
+public:
+	inline
+	__CV_SI2(df_int2 &iValue_) :
+		iValue(iValue_)
+	{
+	}
+
+	inline	df_int2
+	operator=(df_int2 iValue_)
+	{
+		char	*pchSource = (char *) &iValue_;
+		char	*pchDest = (char *) &iValue;
+
+		pchDest[0] = pchSource[1];
+		pchDest[1] = pchSource[0];
+		return iValue_;
+	}
+
+	inline
+	operator df_int2(void) const
+	{
+		df_int2 iValue_;
+
+		char	*pchSource = (char *) &iValue;
+		char	*pchDest = (char *) &iValue_;
+
+		pchDest[0] = pchSource[1];
+		pchDest[1] = pchSource[0];
+		return iValue_;
+	}
+};
+#endif
+
+#endif
diff -uN no-docfile/dfess.cpp docfile/dfess.cpp
--- no-docfile/dfess.cpp	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dfess.cpp	2004-02-05 08:58:21.000000000 +1100
@@ -0,0 +1,129 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+static char const *rcsid = "$Id: dfess.cpp,v 1.4 2002/01/23 05:51:43 borgia Exp $";
+#include "docfile.h"
+#include "dfmgr.h"
+#include "dfess.h"
+#include <stdlib.h>
+#include <string.h>
+
+
+DocFileEnumStatStg::DocFileEnumStatStg( DocFileStorage *pdfs_,
+					HRESULT &hr) :
+	pdfs(pdfs_),
+	iStackPtr(0)
+{
+	pdfs->AddRef();
+	hr = Reset();
+}
+
+DocFileEnumStatStg::DocFileEnumStatStg( DocFileEnumStatStg *pdfess) :
+	pdfs(pdfess->pdfs),
+	iStackPtr(pdfess->iStackPtr)
+{
+	memcpy(aiStack, pdfess->aiStack, sizeof(aiStack[0]) * iStackPtr);
+}
+
+DocFileEnumStatStg::~DocFileEnumStatStg(void)
+{
+	pdfs->Release();
+}
+
+DEFINE_REFCOUNT(DocFileEnumStatStg)
+
+HRESULT
+DocFileEnumStatStg::DescendLeft(df_int4 iEntry)
+{
+	HRESULT hr;
+	DocFile_DirEnt dfde;
+
+	if (iEntry == -1)
+		return S_OK;
+
+	aiStack[iStackPtr] = iEntry;
+	iStackPtr++;
+	hr = pdfs->pdfm->GetDirectoryEntry(iEntry, &dfde);
+	if (!hr)
+		hr = DescendLeft(SI4(dfde.iLeftSibling));
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileEnumStatStg::Reset(void)
+{
+	HRESULT hr;
+	DocFile_DirEnt dfde;
+
+	iStackPtr = 0;
+	hr = pdfs->pdfm->GetDirectoryEntry(pdfs->GetEntryNumber(), &dfde);
+	if (!hr)
+	{
+		hr = DescendLeft(SI4(dfde.iFirstChild));
+	}
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileEnumStatStg::Clone(IEnumSTATSTG **ppiess)
+{
+	HRESULT hr;
+
+	*ppiess = new DocFileEnumStatStg(this);
+	if (hr)
+		(*ppiess)->Release();
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileEnumStatStg::Next(	ULONG	nElems,
+				STATSTG *pss,
+				ULONG	*pnFetched)
+{
+	DocFile_DirEnt	dfde;
+	HRESULT hr = 0;
+
+	if (pnFetched)
+		*pnFetched = 0;
+	while (iStackPtr && nElems && !hr)
+	{
+		iStackPtr--;
+		hr = pdfs->pdfm->GetDirectoryEntry(aiStack[iStackPtr], &dfde);
+		if (hr == 0)
+		{
+			if (pss)
+			{
+				PopulateStatStg(pss, TRUE, dfde);
+				pss++;
+			}
+			if (pnFetched)
+				(*pnFetched)++;
+			hr = DescendLeft(SI4(dfde.iRightSibling));
+			nElems--;
+		}
+	}
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileEnumStatStg::Skip(ULONG nElems)
+{
+	return Next(nElems, 0, 0);
+}
+
diff -uN no-docfile/dfess.h docfile/dfess.h
--- no-docfile/dfess.h	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dfess.h	2004-02-05 09:00:34.000000000 +1100
@@ -0,0 +1,46 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+class DocFileEnumStatStg : public IEnumSTATSTG, public DocFileReferenceCounter, public DocFileInternalFunctions
+{
+private:
+	DocFileStorage		*pdfs;
+	int			iStackPtr;
+	df_int4			aiStack[256];
+
+	DocFileEnumStatStg( DocFileEnumStatStg *pdfess);
+	~DocFileEnumStatStg(void);
+
+	HRESULT DF_STDCALL QueryInterface(REFIID	riid,
+			void		**ppvObj);
+	ULONG	DF_STDCALL AddRef(void) ;
+	ULONG	DF_STDCALL Release(void);
+
+	HRESULT DescendLeft(df_int4	iEntry);
+	HRESULT DF_STDCALL Reset(void);
+	HRESULT DF_STDCALL Clone(IEnumSTATSTG **ppiess);
+	HRESULT DF_STDCALL Next(	ULONG	nElems,
+				STATSTG *pss,
+				ULONG	*pnFetched);
+	HRESULT DF_STDCALL Skip(ULONG nElems);
+
+public:
+	DocFileEnumStatStg(	DocFileStorage *pdfs_,
+					HRESULT &hr);
+};
diff -uN no-docfile/dfint.cpp docfile/dfint.cpp
--- no-docfile/dfint.cpp	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dfint.cpp	2004-02-05 08:58:26.000000000 +1100
@@ -0,0 +1,215 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+static char const *rcsid = "$Id: dfint.cpp,v 1.4 1999/01/20 02:58:07 troy Exp $";
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <time.h>
+#include "docfile.h"
+
+
+HRESULT
+DocFileInternalFunctions::Translate(	ULARGE_INTEGER	*piULARGE,
+					LONG		i)
+{
+	piULARGE->u.HighPart = 0;
+	piULARGE->u.LowPart = i;
+	return 0;
+}
+
+HRESULT
+DocFileInternalFunctions::Translate(	LONG		*pi,
+					ULARGE_INTEGER const *piULARGE)
+{
+	if (piULARGE->u.HighPart)
+		return E_FAIL;
+	*pi = piULARGE->u.LowPart;
+	return 0;
+}
+
+
+HRESULT
+DocFileInternalFunctions::Translate(	LARGE_INTEGER	*piLARGE,
+					LONG		i)
+{
+	piLARGE->u.HighPart = 0;
+	piLARGE->u.LowPart = i;
+	return 0;
+}
+
+HRESULT
+DocFileInternalFunctions::Translate(	LONG		*pi,
+					LARGE_INTEGER const *piLARGE)
+{
+	if (piLARGE->u.HighPart)
+		return E_FAIL;
+	*pi = piLARGE->u.LowPart;
+	return 0;
+}
+
+
+HRESULT
+DocFileInternalFunctions::Translate(	FILETIME	*pft,
+					LONG		i)
+{
+	ULARGE_INTEGER	uli;
+	LONGLONG	iTmp;
+
+	uli.QuadPart = iTmp;
+	iTmp = 86400l;
+	iTmp *= 134774l;
+	iTmp += i;
+	iTmp *= 10000000;
+	uli.QuadPart = iTmp;
+	pft->dwLowDateTime = uli.u.LowPart;
+	pft->dwHighDateTime = uli.u.HighPart;
+	return 0;
+}
+
+HRESULT
+DocFileInternalFunctions::Translate(	LONG		*pi,
+					FILETIME const	*pft)
+{
+	ULARGE_INTEGER	uli;
+	LONGLONG	iTmp, iTmp2;
+
+	uli.u.LowPart = pft->dwLowDateTime;
+	uli.u.HighPart = pft->dwHighDateTime;
+	iTmp = uli.QuadPart;
+	iTmp /= 10000000;
+	iTmp2 = 86400l;
+	iTmp2 *= 134774l;
+	iTmp -= iTmp2;
+	*pi = iTmp;
+	return 0;
+}
+
+
+void
+DocFileInternalFunctions::GetTimeNow(FILETIME &ft)
+{
+	time_t		t;
+
+	time(&t);
+	Translate(&ft, t);
+}
+
+HRESULT
+DocFileInternalFunctions::TranslateError(void)
+{
+	switch(errno)
+	{
+#ifdef EPERM
+	case EPERM:
+		return E_FAIL;
+#endif
+#ifdef ENOENT
+	case ENOENT:
+		return STG_E_FILENOTFOUND;
+#endif
+#ifdef ENOMEM
+	case ENOMEM:
+		return STG_E_INSUFFICIENTMEMORY;
+#endif
+#ifdef EEXIST
+	case EEXIST:
+		return STG_E_FILEALREADYEXISTS;
+#endif
+#ifdef ENOTDIR
+	case ENOTDIR:
+		return STG_E_FILENOTFOUND;
+#endif
+	}
+	return E_FAIL;
+}
+
+void
+DocFileInternalFunctions::PopulateStatStg(	STATSTG *pss,
+						BOOL	bIncludeName,
+						DocFile_DirEnt &dfde)
+{
+	df_int4 i1;
+	df_int2 i2;
+
+	if (bIncludeName)
+	{
+		df_char_t	achName[DF_NAMELEN];
+
+		GetName(&dfde, achName);
+		// FIXME - Needs to use the OleAllocate functions in Windows
+		pss->pwcsName = (df_char_t *) malloc((df_strlen(achName) + 1) * sizeof(df_char_t));
+		df_strcpy(pss->pwcsName, achName);
+	}
+	else
+	{
+		pss->pwcsName = 0;
+	}
+	switch(dfde.iFileType)
+	{
+	case DF_FT_ROOT:
+	case DF_FT_STORAGE:
+		pss->type = STGTY_STORAGE;
+		break;
+
+	case DF_FT_STREAM:
+		pss->type = STGTY_STREAM;
+		break;
+	}
+	Translate(&pss->cbSize, SI4(dfde.iFileSize));
+	pss->mtime.dwHighDateTime = SI4(dfde.iModifiedHigh);
+	pss->mtime.dwLowDateTime = SI4(dfde.iModifiedLow);
+	pss->ctime.dwHighDateTime = SI4(dfde.iCreatedHigh);
+	pss->ctime.dwLowDateTime = SI4(dfde.iCreatedLow);
+	pss->atime = pss->mtime;
+	pss->grfMode = 0;
+	pss->grfLocksSupported = 0;
+
+	memcpy(&i1, dfde.achClassID, 4);
+	pss->clsid.Data1 = SI4(i1);
+	memcpy(&i2, dfde.achClassID + 4, 2);
+	pss->clsid.Data2 = SI2(i2);
+	memcpy(&i2, dfde.achClassID + 6, 2);
+	pss->clsid.Data3 = SI2(i2);
+	memcpy(pss->clsid.Data4, dfde.achClassID + 8, 8);
+	pss->grfStateBits = SI4(dfde.iStateBits);
+	pss->reserved = 0;
+}
+
+void
+DocFileInternalFunctions::GetName(	DocFile_DirEnt	*pdfde,
+					df_char_t	*pchName)
+{
+	int	i;
+	df_int2 iChar;
+	int	iLen;
+
+	iLen = SI2(pdfde->iNameLen) / 2 - 1;
+
+	for (i = 0; i < iLen; i++)
+	{
+		iChar = pdfde->achEntryName[i];
+		pchName[i] = SI2(iChar);
+	}
+	pchName[iLen] = 0;
+}
+
+
+
diff -uN no-docfile/dfmgr.cpp docfile/dfmgr.cpp
--- no-docfile/dfmgr.cpp	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dfmgr.cpp	2004-02-05 08:58:34.000000000 +1100
@@ -0,0 +1,1823 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+static char const *rcsid = "$Id: dfmgr.cpp,v 1.6 1999/01/20 02:58:07 troy Exp $";
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include "dfmgr.h"
+#include "redblack.h"
+#define FILE_LEVEL_THRESHOLD	4096
+
+static	DF_StreamType	dfstDirectory(DFST_Directory);
+static	DF_StreamType	dfstDataVTOC(DFST_DataVTOC);
+static	DF_StreamType	dfstData(DFST_Data);
+
+DocFileManager::DocFileManager(ILockBytes *pilb_) :
+	pilb(pilb_),
+	nHeaderRef(0),
+	iVTOCSize(0),
+	pchVTOC(0),
+	iLowestFreeStreamBlock(0),
+	nExtVTOCs(0)
+{
+	pilb->AddRef();
+}
+
+DocFileManager::~DocFileManager(void)
+{
+	if (pchVTOC)
+		delete [] pchVTOC;
+	pilb->Release();
+}
+
+DEFINE_REFCOUNT(DocFileManager)
+
+HRESULT
+DocFileManager::GetBlock(	void	*pvData,
+				long	iBlock)
+{
+	ULARGE_INTEGER	iBlock_;
+	DWORD	nRead;
+	HRESULT hr;
+
+	hr = Translate(&iBlock_, (iBlock + 1) * DF_BLOCK_SIZE);
+	if (hr)
+		return hr;
+	return pilb->ReadAt(iBlock_, pvData, DF_BLOCK_SIZE, &nRead);
+}
+
+HRESULT
+DocFileManager::SetBlock(	void const	*pvData,
+				long		iBlock)
+{
+	ULARGE_INTEGER	iBlock_;
+	DWORD	nWritten;
+	HRESULT hr;
+
+	hr = Translate(&iBlock_, (iBlock + 1) * DF_BLOCK_SIZE);
+	if (hr)
+		return hr;
+	return pilb->WriteAt(iBlock_, pvData, DF_BLOCK_SIZE, &nWritten);
+}
+
+HRESULT
+DocFileManager::LockBlock(	long	iBlock,
+				DWORD	dwLockType)
+{
+	ULARGE_INTEGER	iBlock_;
+	ULARGE_INTEGER	nBytes;
+	HRESULT hr;
+
+	hr = Translate(&iBlock_, iBlock * DF_BLOCK_SIZE);
+	if (!hr)
+		hr = Translate(&nBytes, DF_BLOCK_SIZE);
+	if (hr)
+		return hr;
+	return pilb->LockRegion(iBlock_, nBytes, dwLockType);
+}
+
+HRESULT
+DocFileManager::UnlockBlock(	long	iBlock,
+				DWORD	dwLockType)
+{
+	ULARGE_INTEGER	iBlock_;
+	ULARGE_INTEGER	nBytes;
+	HRESULT hr;
+
+	hr = Translate(&iBlock_, (iBlock + 1) * DF_BLOCK_SIZE);
+	if (!hr)
+		hr = Translate(&nBytes, DF_BLOCK_SIZE);
+	if (hr)
+		return hr;
+	return pilb->UnlockRegion(iBlock_, nBytes, dwLockType);
+}
+
+HRESULT
+DocFileManager::InitOldFile(void)
+{
+	HRESULT hr;
+	df_int4 nVTOCs;
+	df_int4 i;
+	DocFile_VTOC dfvt;
+	char	*pchNow;
+	df_int4 iCurrentVTOC = -1;
+	df_int4 iVTOCBlock;
+
+	hr = GetHeader();
+	if (hr)
+		return hr;
+
+	nVTOCs = SI4(dfh.nVTOCs);
+
+	iVTOCBlock = SI4(dfh.iExtendedVTOC);
+	i = SI4(dfh.iExtendedVTOCSize);
+
+	while ( i-- &&
+		iVTOCBlock != DF_VTOC_EOF &&
+		iVTOCBlock != DF_VTOC_FREE)
+	{
+		aiExtVTOCs[nExtVTOCs++] = iVTOCBlock;
+		hr = GetBlock(&dfvt, iVTOCBlock);
+		if (hr)
+			iVTOCBlock = DF_VTOC_EOF;
+		else
+			iVTOCBlock = SI4(dfvt.aiBlocks[DF_VTOC_SIZE - 1]);
+	}
+
+	iVTOCSize = nVTOCs * 0x10;
+
+	pchVTOC = new char[iVTOCSize];
+	pchNow = pchVTOC;
+
+	for (i = 0; i < nVTOCs; i++)
+	{
+		int	j;
+		df_int4 iVTOCBlock = FindVTOCBlock(i);
+
+		hr = GetBlock(&dfvt, iVTOCBlock);
+		if (hr)
+		{
+			for (j = 0; j < DF_VTOC_SIZE; j++)
+			{
+				if (SI4(dfvt.aiBlocks[j]) != DF_VTOC_FREE)
+				{
+					int	iBitValue = 1 << (j % 8);
+
+					*pchNow |= iBitValue;
+					if (iBitValue == 128)
+						pchNow++;
+				}
+			}
+		}
+		else
+		{
+			memset(pchNow, -1, 0x10);
+			pchNow += 0x10;
+		}
+	}
+
+	for (i = 0; i < 3; i++)
+	{
+		df_int4 iNextBlock;
+		df_int4 iBlockNum;
+
+		switch(i)
+		{
+		case 0:
+			iNextBlock = SI4(dfh.iFirstDirBlock);
+			break;
+
+		case 1:
+			iNextBlock = SI4(dfh.iFirstDataVTOC);
+			break;
+
+		case 2:
+			{
+				DocFile_DirEnt	dfde;
+
+				hr = GetDirectoryEntry(0, &dfde);
+				if (hr)
+					iNextBlock = DF_VTOC_EOF;
+				else
+					iNextBlock = SI4(dfde.iVTOCPosition);
+			}
+			break;
+		}
+		iBlockNum = 0;
+		while (iNextBlock != DF_VTOC_EOF)
+		{
+			df_int4 iNextVTOC;
+
+			adfsi[i].SetBlock(iBlockNum++, iNextBlock);
+			iNextVTOC = iNextBlock / DF_VTOC_SIZE;
+			if (iNextVTOC != iCurrentVTOC)
+			{
+				df_int4 iVTOCBlock = FindVTOCBlock(iNextVTOC);
+
+				GetBlock(&dfvt, iVTOCBlock);
+				iCurrentVTOC = iNextVTOC;
+			}
+			iNextBlock = SI4(dfvt.aiBlocks[iNextBlock % DF_VTOC_SIZE]);
+		}
+	}
+
+	hr = ReleaseHeader(FALSE);
+	return hr;
+}
+
+
+void
+DocFileManager::InitNewFile(void)
+{
+	DocFile_VTOC	dfvt;
+	DocFile_DirEnt	adfde[DF_DE_PER_BLOCK];
+	FILETIME	ft;
+	df_int4		nWritten;
+
+	nHeaderRef = 1;
+
+	dfh.iMagic1 = 0xd0;
+	dfh.iMagic2 = 0xcf;
+	dfh.iMagic3 = 0x11;
+	dfh.iMagic4 = 0xe0;
+	dfh.iMagic5 = 161;
+	dfh.iMagic6 = 177;
+	dfh.iMagic7 = 26;
+	dfh.iMagic8 = 225;
+	SI4(dfh.aiUnknown1[0]) = 0;
+	SI4(dfh.aiUnknown1[1]) = 0;
+	SI4(dfh.aiUnknown1[2]) = 0;
+	SI4(dfh.aiUnknown1[3]) = 0;
+	SI4(dfh.iVersion) = 0x3003e;
+	SI4(dfh.aiUnknown2[0]) = 0x9fffe;
+	SI4(dfh.aiUnknown2[1]) = 6;
+	SI4(dfh.aiUnknown2[2]) = 0;
+	SI4(dfh.aiUnknown2[3]) = 0;
+	SI4(dfh.nVTOCs) = 0;
+	SI4(dfh.iFirstDirBlock) = 0;
+	SI4(dfh.aiUnknown3[0]) = 0;
+	SI4(dfh.aiUnknown3[1]) = 0x1000; // Could this be the threshold for storage as a file level stream?
+	SI4(dfh.iFirstDataVTOC) = 0xfffffffe;
+	SI4(dfh.iHasData) = 0;
+	SI4(dfh.iExtendedVTOC) = 0xfffffffe;
+	SI4(dfh.iExtendedVTOCSize) = 0;
+	memset(dfh.aiVTOCofVTOCs, 0xff, sizeof(dfh.aiVTOCofVTOCs));
+	ReleaseHeader(TRUE);
+	GetHeader();
+
+	InitDirBlock(adfde);
+#if defined(_Windows) || defined(__WIN32) || defined(_WIN32) || defined(WIN32)
+	SetName(adfde, L"Root Entry");
+#else
+	SetName(adfde, "Root Entry");
+#endif
+	adfde[0].iFileType = DF_FT_ROOT;
+	GetTimeNow(ft);
+	SI4(adfde->iCreatedLow) = ft.dwLowDateTime;
+	SI4(adfde->iCreatedHigh) = ft.dwHighDateTime;
+	SI4(adfde->iModifiedLow) = ft.dwLowDateTime;
+	SI4(adfde->iModifiedHigh) = ft.dwHighDateTime;
+	SI4(adfde->iVTOCPosition) = DF_VTOC_EOF;
+	WriteToFileStream(	dfstDirectory,
+				0,
+				adfde,
+				sizeof(adfde),
+				nWritten);
+	ReleaseHeader(FALSE);
+}
+
+void
+DocFileManager::InitDirBlock(	DocFile_DirEnt *pdfde,
+				int	nEntries)
+{
+	int	i;
+
+	memset(pdfde, 0, sizeof(*pdfde) * nEntries);
+
+	for (i = 0; i < nEntries; i++, pdfde++)
+	{
+		SI4(pdfde->iLeftSibling) = -1;
+		SI4(pdfde->iRightSibling) = -1;
+		SI4(pdfde->iFirstChild) = -1;
+	}
+}
+
+void
+DocFileManager::SetName(	DocFile_DirEnt	*pdfde,
+				df_char_t	const *pchName)
+{
+	int	i;
+	df_int2 iChar;
+
+	memset(pdfde->achEntryName, 0, sizeof(pdfde->achEntryName));
+	for (i = 0; pchName[i]; i++)
+	{
+		SI2(iChar) = (df_int2) (unsigned char) pchName[i];
+		pdfde->achEntryName[i] = iChar;
+	}
+	SI2(pdfde->iNameLen) = (df_int2) ((i + 1) * 2);
+}
+
+HRESULT
+DocFileManager::GetDirectoryEntry(	df_int4 iLocation,
+					DocFile_DirEnt *pdfde)
+{
+	df_int4 nRead;
+	HRESULT hr;
+
+	hr = ReadFromFileStream(dfstDirectory,
+				iLocation * sizeof(*pdfde),
+				pdfde,
+				sizeof(*pdfde),
+				nRead);
+	if (hr)
+		return hr;
+	if (nRead < sizeof(*pdfde))
+		return E_FAIL;
+	return S_OK;
+}
+
+HRESULT
+DocFileManager::SetDirectoryEntry(	df_int4 iLocation,
+					DocFile_DirEnt *pdfde)
+{
+	df_int4 nWritten;
+
+	return WriteToFileStream(dfstDirectory,
+				iLocation * sizeof(*pdfde),
+				pdfde,
+				sizeof(*pdfde),
+				nWritten);
+}
+
+HRESULT
+DocFileManager::AnnihilateEntry(df_int4		iEntry,
+				BOOL		bSiblingsToo)
+{
+	DocFile_DirEnt	dfde;
+	HRESULT hr;
+	df_int4 iChild;
+
+	if (iEntry == -1)
+		return S_OK;
+
+	hr = GetDirectoryEntry(iEntry, &dfde);
+	if (!hr)
+	{
+		if (bSiblingsToo)
+		{
+			iChild = SI4(dfde.iLeftSibling);
+			AnnihilateEntry(iChild, TRUE);
+			iChild = SI4(dfde.iRightSibling);
+			AnnihilateEntry(iChild, TRUE);
+		}
+		iChild = SI4(dfde.iFirstChild);
+		AnnihilateEntry(iChild, TRUE);
+		if (dfde.iFileType == DF_FT_STREAM)
+		{
+			if (SI4(dfde.iFileSize) >= FILE_LEVEL_THRESHOLD)
+				hr = FreeFileChain(SI4(dfde.iVTOCPosition));
+			else
+				hr = FreeDataChain(SI4(dfde.iVTOCPosition));
+			if (hr)
+				return hr;
+		}
+		InitDirBlock(&dfde, 1);
+		hr = SetDirectoryEntry(iEntry, &dfde);
+	}
+	return hr;
+}
+
+HRESULT
+DocFileManager::LocateChild(	df_int4		iParentLocation,
+				df_char_t const *pchName,
+				DocFile_DirEnt	&dfde,
+				df_int4		&iEntryLocation,
+				DFLocType	dflt,
+				BOOL		bStart,
+				DF_RBNode	**ppnParent)
+{
+	HRESULT hr;
+	int	iBranch;
+	df_int4 iLeftLocation;
+	df_int4 iRightLocation;
+	int	iCompare;
+	DF_RBNode *pnChild;
+	DF_RBNode *pnParent;
+
+	if (bStart)
+	{
+		pnParent = new DF_RBNode(iParentLocation, 0);
+		hr = pnParent->Populate(this);
+		if (hr)
+		{
+			delete pnParent;
+			return hr;
+		}
+		iBranch = DFRB_LEFT;
+
+		iLeftLocation = SI4(pnParent->GetEntry(this).iFirstChild);
+		iRightLocation = -1;
+	}
+	else
+	{
+		pnParent = *ppnParent;
+		hr = pnParent->Populate(this);
+		if (hr)
+			return hr;
+
+		iLeftLocation = SI4(pnParent->GetEntry(this).iLeftSibling);
+		iRightLocation = SI4(pnParent->GetEntry(this).iRightSibling);
+
+		iCompare = (df_strlen(pchName) + 1) * 2 - SI2(pnParent->GetEntry(this).iNameLen);
+		if (!iCompare)
+		{
+			df_char_t	achName[DF_NAMELEN];
+
+			GetName(&pnParent->GetEntry(this), achName);
+			iCompare = df_stricmp(pchName, achName);
+		}
+
+		if (iCompare == 0)
+		{
+			iEntryLocation = iParentLocation;
+			if (dflt == DFLT_Remove || dflt == DFLT_Delete)
+			{
+				pnParent = *ppnParent = pnParent->Delete(this, FALSE);
+				dfde = pnParent->GetEntry(this);
+			}
+			else
+			{
+				dfde = pnParent->GetEntry(this);
+				if (dflt != DFLT_Find)
+					return STG_E_FILEALREADYEXISTS;
+			}
+			return S_OK;
+		}
+		else if (iCompare < 0)
+		{
+			iBranch = DFRB_LEFT;
+		}
+		else
+		{
+			iBranch = DFRB_RIGHT;
+		}
+	}
+
+	if (iLeftLocation >= 0)
+		pnParent->SetChild(DFRB_LEFT, new DF_RBNode(iLeftLocation, pnParent));
+	if (iRightLocation >= 0)
+		pnParent->SetChild(DFRB_RIGHT, new DF_RBNode(iRightLocation, pnParent));
+	pnChild = pnParent->GetChild(iBranch);
+	if (pnChild)
+	{
+		hr = LocateChild(	pnChild->GetDirEnt(),
+					pchName,
+					dfde,
+					iEntryLocation,
+					dflt,
+					FALSE,
+					&pnChild);
+	}
+	else
+	{
+		/* If we've arrived here, we have failed to find an entry */
+		if (dflt == DFLT_Create || dflt == DFLT_Insert)
+		{
+			DF_RBNode *pnNew;
+
+			df_int4 iNextChildLocation;
+			FILETIME	ft;
+
+			if (dflt == DFLT_Insert)
+			{
+				pnNew = new DF_RBNode(iEntryLocation, 0);
+				hr = 0;
+			}
+			else
+			{
+				iNextChildLocation = 0;
+				do
+				{
+					iEntryLocation = iNextChildLocation++;
+					hr = GetDirectoryEntry(iEntryLocation, &dfde);
+				} while (!hr && SI2(dfde.iNameLen) != 0);
+
+				if (hr)
+				{
+					df_int4 nWritten;
+					DocFile_DirEnt adfde[DF_DE_PER_BLOCK];
+
+					InitDirBlock(adfde);
+
+					hr = WriteToFileStream(dfstDirectory,
+							iEntryLocation * sizeof(adfde),
+							adfde,
+							sizeof(adfde),
+							nWritten);
+				}
+				pnNew = new DF_RBNode(iEntryLocation, 0);
+				pnNew->CreateNew(this);
+				SetName(&pnNew->GetEntry(this), pchName);
+				GetTimeNow(ft);
+				SI4(pnNew->GetEntry(this).iCreatedLow) = ft.dwLowDateTime;
+				SI4(pnNew->GetEntry(this).iCreatedHigh) = ft.dwHighDateTime;
+				SI4(pnNew->GetEntry(this).iModifiedLow) = ft.dwLowDateTime;
+				SI4(pnNew->GetEntry(this).iModifiedHigh) = ft.dwHighDateTime;
+				SI4(pnNew->GetEntry(this).iVTOCPosition) = DF_VTOC_EOF;
+			}
+			if (!hr)
+			{
+				pnNew->Populate(this);
+				pnNew->SetChild(DFRB_LEFT, 0);
+				pnNew->SetChild(DFRB_RIGHT, 0);
+				pnNew->InsertInto(pnParent, iBranch, this);
+				dfde = pnNew->GetEntry(this);
+			}
+			else
+			{
+				delete pnNew;
+			}
+		}
+		else
+		{
+			hr = STG_E_PATHNOTFOUND;
+		}
+	}
+	if (bStart)
+	{
+		if (!hr)
+			pnParent->WriteChanges(this);
+		delete pnParent;
+	}
+	return hr;
+}
+
+HRESULT
+DocFileManager::ReadFromFileStream(	DF_StreamType	&dfst,
+					df_int4		iLocation,
+					void		*pvData,
+					df_int4		nBytes,
+					df_int4		&nRead)
+{
+	HRESULT hr = 0;
+	char	achBlock[DF_BLOCK_SIZE];
+	df_int4 nStreamBlocks = GetTotalStreamBlocks(dfst);
+	BOOL	bIStream = (dfst.GetType() == DFST_IStream);
+
+	nRead = 0;
+	while (nBytes)
+	{
+		df_int4 iBlockNow = iLocation / DF_BLOCK_SIZE;
+		df_int4 iLocNow = iLocation % DF_BLOCK_SIZE;
+		df_int4 nBytesNow = DF_BLOCK_SIZE - iLocNow;
+		df_int4 iFileBlock;
+
+		if (nBytesNow > nBytes)
+			nBytesNow = nBytes;
+		if (iBlockNow >= nStreamBlocks)
+			break;
+		iFileBlock = GetStreamBlock(dfst, iBlockNow);
+		if (bIStream)
+		{
+			DocFile_StreamPtr &dfsp = dfst.GetStreamPointer();
+
+			dfsp.iStreamBlock = iFileBlock;
+			dfsp.iPosition = iLocation;
+		}
+		hr = GetBlock(achBlock, iFileBlock);
+		if (hr)
+			break;
+		memcpy( pvData, achBlock + iLocNow, nBytesNow);
+		nBytes -= nBytesNow;
+		nRead += nBytesNow;
+		iLocation += nBytesNow;
+		pvData = (char *) pvData + nBytesNow;
+	}
+	if (bIStream && nRead)
+	{
+		DocFile_StreamPtr &dfsp = dfst.GetStreamPointer();
+		df_int4 iTotalBlockSize = nStreamBlocks * DF_BLOCK_SIZE;
+
+		if (iLocation >= iTotalBlockSize)
+		{
+			df_int4 iLocTmp = iLocation - iTotalBlockSize;
+
+			dfsp.iStreamBlock = GetStreamBlock(dfst,nStreamBlocks - 1);
+			dfsp.iExtraBlocks = 0;
+			while (iLocTmp >= 0)
+				iLocTmp -= DF_BLOCK_SIZE, dfsp.iExtraBlocks++;
+		}
+		else
+		{
+			dfsp.iExtraBlocks = 0;
+			dfsp.iStreamBlock = GetStreamBlock(dfst, iLocation / DF_BLOCK_SIZE);
+		}
+		dfsp.iPosition = iLocation;
+	}
+	return hr;
+}
+
+HRESULT
+DocFileManager::WriteToFileStream(	DF_StreamType	&dfst,
+					df_int4		iLocation,
+					void const	*pvData,
+					df_int4		nBytes,
+					df_int4		&nWritten)
+{
+	HRESULT hr = 0;
+	char	achBlock[DF_BLOCK_SIZE];
+	BOOL	bIStream = (dfst.GetType() == DFST_IStream);
+	df_int4 nStreamBlocks = GetTotalStreamBlocks(dfst);
+
+	nWritten = 0;
+	while (nBytes)
+	{
+		df_int4 iBlockNow = iLocation / DF_BLOCK_SIZE;
+		df_int4 iLocNow = iLocation % DF_BLOCK_SIZE;
+		df_int4 nBytesNow = DF_BLOCK_SIZE - iLocNow;
+		df_int4 iFileBlock;
+
+		if (nBytesNow < 0)
+			nBytes = nBytesNow = 0;
+		else if (nBytesNow > nBytes)
+			nBytesNow = nBytes;
+		if (iBlockNow >= nStreamBlocks)
+		{
+			hr = ExtendFileStream(dfst, iBlockNow);
+			nStreamBlocks = iBlockNow + 1;
+			if (hr)
+				break;
+		}
+		iFileBlock = GetStreamBlock(dfst, iBlockNow);
+		if (bIStream)
+		{
+			DocFile_StreamPtr &dfsp = dfst.GetStreamPointer();
+
+			dfsp.iStreamBlock = iFileBlock;
+			dfsp.iPosition = iLocation;
+			dfsp.iExtraBlocks = 0;
+		}
+		if (nBytesNow != DF_BLOCK_SIZE)
+		{
+			hr = GetBlock(achBlock, iFileBlock);
+			if (hr)
+				break;
+		}
+		memcpy(achBlock + iLocNow, pvData, nBytesNow);
+		SetBlock(achBlock, iFileBlock);
+		nBytes -= nBytesNow;
+		nWritten += nBytesNow;
+		iLocation += nBytesNow;
+		pvData = (char const *) pvData + nBytesNow;
+	}
+	if (bIStream)
+	{
+		DocFile_StreamPtr &dfsp = dfst.GetStreamPointer();
+
+		if (iLocation == nStreamBlocks * DF_BLOCK_SIZE)
+		{
+			dfsp.iStreamBlock = GetStreamBlock(dfst, nStreamBlocks - 1);
+			dfsp.iExtraBlocks = 1;
+		}
+		else
+		{
+			dfsp.iStreamBlock = GetStreamBlock(dfst, iLocation / DF_BLOCK_SIZE);
+			dfsp.iExtraBlocks = 0;
+		}
+		dfsp.iPosition = iLocation;
+	}
+	return hr;
+}
+
+
+int
+DocFileManager::StreamTypeToIndex(DF_StreamType &dfst)
+{
+	switch(dfst.GetType())
+	{
+	case DFST_Directory:
+		return 0;
+
+	case DFST_DataVTOC:
+		return 1;
+
+	case DFST_Data:
+		return 2;
+	}
+	*(char *) 0 = 0;
+	return -1;
+}
+
+df_int4
+DocFileManager::GetTotalStreamBlocks(DF_StreamType &dfst)
+{
+	if (dfst.GetType() == DFST_IStream)
+		return dfst.GetTotalBlocks();
+	return adfsi[StreamTypeToIndex(dfst)].GetTotalBlocks();
+}
+
+df_int4
+DocFileManager::GetStreamBlock( DF_StreamType	&dfst,
+				df_int4		iBlockNum)
+{
+	if (dfst.GetType() == DFST_IStream)
+	{
+		df_int4 iBlockNow;
+		df_int4 iFileBlockNow;
+		df_int4 iVTOCBlock;
+		DocFile_StreamPtr &dfsp = dfst.GetStreamPointer();
+		DocFile_DirEnt &dfde = dfst.GetDirEnt();
+
+		if (iBlockNum == 0)
+			return SI4(dfde.iVTOCPosition);
+
+		if (dfsp.iStreamBlock != -1 &&
+		    (iBlockNow = dfsp.iPosition / DF_BLOCK_SIZE - dfsp.iExtraBlocks) <= iBlockNum)
+		{
+
+			if (iBlockNow == iBlockNum)
+				return dfsp.iStreamBlock;
+			iFileBlockNow = dfsp.iStreamBlock;
+		}
+		else
+		{
+			iBlockNow = 0;
+			iFileBlockNow = SI4(dfde.iVTOCPosition);
+		}
+
+		while (iBlockNow < iBlockNum)
+		{
+			HRESULT hr;
+			DocFile_VTOC	dfvt;
+
+			iVTOCBlock = FindVTOCBlock(iFileBlockNow / DF_VTOC_SIZE);
+			hr = GetBlock(&dfvt, iVTOCBlock);
+			if (hr)
+				return -2;
+			iFileBlockNow = SI4(dfvt.aiBlocks[iFileBlockNow % DF_VTOC_SIZE]);
+			iBlockNow++;
+		}
+		return iFileBlockNow;
+	}
+	return adfsi[StreamTypeToIndex(dfst)].GetBlock(iBlockNum);
+}
+
+HRESULT
+DocFileManager::ExtendFileStream(DF_StreamType &dfst,
+				df_int4		iBlockNum)
+{
+	df_int4 i;
+	int	iBit;
+	int	iBitValue;
+	HRESULT hr = 0;
+	DocFile_VTOC dfvt;
+	char	achZeroes[DF_BLOCK_SIZE];
+	df_int4 iLinkBlock;
+
+	memset(achZeroes, 0, DF_BLOCK_SIZE);
+
+	i = GetTotalStreamBlocks(dfst);
+
+	if (i)
+		iLinkBlock = GetStreamBlock(dfst, i - 1);
+	else
+		iLinkBlock = -1;
+
+	for (; i <= iBlockNum; i++)
+	{
+		df_int4 j;
+		df_int4 iBlock;
+		int	iVTOCBlock;
+
+		for (j = 0;
+		     j < iVTOCSize && !((~((int) pchVTOC[j])) & 0xff);
+		     j++);
+		if (j == iVTOCSize)
+			ExtendVTOC();
+		for (iBit = 0, iBitValue = 1;
+		     pchVTOC[j] & iBitValue;
+		     iBit++, iBitValue <<= 1);
+		pchVTOC[j] |= iBitValue;
+		iBlock = j * 8 + iBit;
+		hr = SetBlock(achZeroes, iBlock);
+		if (hr)
+			break;
+		iVTOCBlock = FindVTOCBlock(iBlock / DF_VTOC_SIZE);
+		hr = GetBlock(&dfvt, iVTOCBlock);
+		if (hr)
+			break;
+		SI4(dfvt.aiBlocks[iBlock % DF_VTOC_SIZE]) = DF_VTOC_EOF;
+		hr = SetBlock(&dfvt, iVTOCBlock);
+		if (hr)
+			break;
+		if (dfst.GetType() != DFST_IStream)
+			adfsi[StreamTypeToIndex(dfst)].SetBlock(i, iBlock);
+		else
+			dfst.AddedBlock();
+		if (iLinkBlock != -1)
+		{
+			iVTOCBlock = FindVTOCBlock(iLinkBlock / DF_VTOC_SIZE);
+			hr = GetBlock(&dfvt, iVTOCBlock);
+			if (hr)
+				break;
+			SI4(dfvt.aiBlocks[iLinkBlock % DF_VTOC_SIZE]) = iBlock;
+			hr = SetBlock(&dfvt, iVTOCBlock);
+		}
+		else
+		{
+			hr = GetHeader();
+			if (!hr)
+			{
+				BOOL bChanged = FALSE;
+
+				switch(dfst.GetType())
+				{
+				case DFST_Directory:
+					SI4(dfh.iFirstDirBlock) = iBlock;
+					bChanged = TRUE;
+					break;
+
+				case DFST_DataVTOC:
+					SI4(dfh.iFirstDataVTOC) = iBlock;
+					SI4(dfh.iHasData) = 1;
+					bChanged = TRUE;
+					break;
+
+				case DFST_Data:
+					{
+						DocFile_DirEnt	dfde;
+
+						GetDirectoryEntry(0, &dfde);
+						j = SI4(dfh.iFirstDirBlock);
+						SI4(dfde.iVTOCPosition) = iBlock;
+						SetDirectoryEntry(0, &dfde);
+					}
+					break;
+
+				case DFST_IStream:
+					SI4(dfst.GetDirEnt().iVTOCPosition) = iBlock;
+					break;
+				}
+				hr = ReleaseHeader(bChanged);
+			}
+		}
+		iLinkBlock = iBlock;
+	}
+	return hr;
+}
+
+df_int4
+DocFile_StreamInfo::GetBlock(df_int4 iBlock)
+{
+	unsigned char *pchLoc = pchBlocks + iBlock * 3;
+
+	return (df_int4) pchLoc[0] +
+		(df_int4) pchLoc[1] * 256 +
+		(df_int4) pchLoc[2] * 65536;
+}
+
+void
+DocFile_StreamInfo::SetBlock(	df_int4 iBlock,
+				df_int4 iFileBlock)
+{
+	unsigned char	*pchLoc;
+
+	if (iBlock >= nPositions)
+	{
+		df_int4 nPositionsNew = nPositions;
+		unsigned char *pchNew;
+
+		while (nPositionsNew <= iBlock)
+		{
+			if (nPositionsNew == 0)
+				nPositionsNew = 64;
+			else
+				nPositionsNew <<= 1;
+		}
+		pchNew = new unsigned char[nPositionsNew * 3];
+		memcpy(pchNew, pchBlocks, nPositions * 3);
+		if (pchBlocks)
+			delete [] pchBlocks;
+		pchBlocks = pchNew;
+		nPositions = nPositionsNew;
+	}
+	pchLoc = pchBlocks + iBlock * 3;
+	pchLoc[0] = iFileBlock & 0xff;
+	pchLoc[1] = (iFileBlock & 0xff00) >> 8;
+	pchLoc[2] = (iFileBlock & 0xff0000) >> 16;
+	if (iBlock >= nBlocks)
+		nBlocks = iBlock + 1;
+}
+
+df_int4
+DocFileManager::FindVTOCBlock(df_int4 iBlock)
+{
+	df_int4 iValue;
+	HRESULT hr = GetHeader();
+
+	if (hr)
+		return -2;
+	if (iBlock < TOTAL_SIMPLE_VTOCS)
+	{
+		iValue = SI4(dfh.aiVTOCofVTOCs[iBlock]);
+	}
+	else
+	{
+		int	iExtBlock = 0;
+		int	iSize = TOTAL_SIMPLE_VTOCS;
+		DocFile_VTOC dfvt;
+
+		do
+		{
+			iBlock -= iSize;
+			iSize = DF_VTOC_SIZE - 1;
+		} while (iBlock >= iSize && ++iExtBlock);
+
+		iValue = -2;
+		if (iExtBlock < nExtVTOCs)
+		{
+			hr = GetBlock(&dfvt, aiExtVTOCs[iExtBlock]);
+			if (!hr)
+				iValue = SI4(dfvt.aiBlocks[iBlock]);
+		}
+	}
+	hr = ReleaseHeader(FALSE);
+	if (hr)
+		return -2;
+	return iValue;
+}
+
+HRESULT
+DocFileManager::ExtendVTOC(void)
+{
+	HRESULT hr;
+	DocFile_VTOC	dfvt;
+	char	*pchVTOCNew;
+	df_int4 nBlocks;
+	df_int4 iVTOCBlock;
+	df_int4 iExtVTOCBlock = -1;
+
+	hr = GetHeader();
+	if (hr)
+		return hr;
+	nBlocks = iVTOCSize / 0x10;	/* * 8 / DF_VTOC_SIZE */
+	iVTOCBlock = nBlocks * DF_VTOC_SIZE;
+
+	memset(&dfvt, -1, sizeof(dfvt));
+	SI4(dfvt.aiBlocks[0]) = DF_VTOC_VTOC;
+	if (nBlocks < TOTAL_SIMPLE_VTOCS)
+	{
+		SI4(dfh.aiVTOCofVTOCs[nBlocks]) = iVTOCBlock;
+	}
+	else
+	{
+		df_int4 iExtBlock = 0;
+		df_int4 iBlock = nBlocks;
+		int	iSize = TOTAL_SIMPLE_VTOCS;
+		DocFile_VTOC dfvtExt;
+
+		do // On RISC platforms this is actually faster than doing both % and /
+		   // when the modulus is not a power of 2
+		{
+			iBlock -= iSize;
+			iSize = DF_VTOC_SIZE - 1;
+		} while (iBlock >= iSize && ++iExtBlock);
+
+		if (iBlock)
+		{
+			if (GetBlock(&dfvtExt, aiExtVTOCs[iExtBlock]))
+				*(char *) 0 = 0;
+		}
+		else
+		{
+			iExtVTOCBlock = iVTOCBlock + 1;
+
+			if (iExtBlock)
+			{
+				if (GetBlock(&dfvtExt, aiExtVTOCs[iExtBlock - 1]))
+					*(char *) 0 = 0;
+				SI4(dfvtExt.aiBlocks[DF_VTOC_SIZE - 1]) = iExtVTOCBlock;
+				if (SetBlock(&dfvtExt, aiExtVTOCs[iExtBlock - 1]))
+					*(char *) 0 = 0;
+			}
+			else
+			{
+				SI4(dfh.iExtendedVTOC) = iExtVTOCBlock;
+			}
+			aiExtVTOCs[nExtVTOCs++] = iExtVTOCBlock;
+			SI4(dfh.iExtendedVTOCSize) = nExtVTOCs;
+			SI4(dfvt.aiBlocks[1]) = DF_EXT_VTOC;
+			memset(&dfvtExt, -1, sizeof(dfvtExt));
+		}
+		SI4(dfvtExt.aiBlocks[iBlock]) = iVTOCBlock;
+		if (SetBlock(&dfvtExt, aiExtVTOCs[iExtBlock]))
+			*(char *) 0 = 0;
+	}
+	SetBlock(&dfvt, iVTOCBlock);
+	SI4(dfh.nVTOCs) = nBlocks + 1;
+	pchVTOCNew = new char[iVTOCSize + 0x10];
+	memcpy(pchVTOCNew, pchVTOC, iVTOCSize);
+	memset(pchVTOCNew + iVTOCSize, 0, 0x10);
+	if (iExtVTOCBlock != -1)
+		pchVTOCNew[iVTOCSize] = 3;
+	else
+		pchVTOCNew[iVTOCSize] = 1;
+	if (pchVTOC)
+		delete [] pchVTOC;
+	pchVTOC = pchVTOCNew;
+	iVTOCSize += 0x10;
+	hr = ReleaseHeader(TRUE);
+	return hr;
+}
+
+
+HRESULT
+DocFileManager::StreamSeek(	DocFile_StreamPtr &dfsp_,
+				df_int4 iLoc,
+				df_int4 *piNewLoc,
+				int	iWhence)
+{
+	long	iNewLoc;
+	long	iBlockOld;
+	long	iBlockNew;
+	DocFile_DirEnt dfde;
+	HRESULT hr;
+	int	iRewind = 0;
+	DocFile_StreamPtr dfsp = dfsp_;
+	int	iBlockSize;
+	df_int4 iEOF;
+
+	hr = GetDirectoryEntry(dfsp.iDirectoryEntry, &dfde);
+	if (hr)
+		return hr;
+	iEOF = SI4(dfde.iFileSize);
+	if (iEOF >= FILE_LEVEL_THRESHOLD)
+		dfsp.bFileStream = TRUE;
+	iBlockSize = dfsp.bFileStream ? DF_BLOCK_SIZE : DF_STREAM_BLOCK_SIZE;
+	switch(iWhence)
+	{
+	case 0:
+		iNewLoc = iLoc;
+		break;
+
+	case 1:
+		iNewLoc = dfsp.iPosition + iLoc;
+		break;
+
+	case 2:
+		iNewLoc = iEOF + iLoc;
+		break;
+	}
+
+	if (dfsp.iStreamBlock == -1)
+		iRewind = 1;
+
+	iBlockNew = iNewLoc / iBlockSize;
+	if (dfsp.iPosition == -1)
+	{
+		iRewind = 1;
+	}
+	else
+	{
+		iBlockOld = dfsp.iPosition / iBlockSize;
+		if (iBlockOld > iBlockNew)
+			iRewind = 1;
+	}
+	if (iRewind)
+	{
+		dfsp.iPosition = 0;
+		dfsp.iStreamBlock = SI4(dfde.iVTOCPosition);
+		if (dfsp.iStreamBlock == DF_VTOC_EOF)
+			dfsp.iExtraBlocks = 1;
+		else
+			dfsp.iExtraBlocks = 0;
+		iBlockOld = 0;
+	}
+
+	if (dfsp.bFileStream)
+	{
+		DF_StreamType	dfst(dfsp, dfde);
+		df_int4		nBlocks = GetTotalStreamBlocks(dfst);
+		df_int4		iBlock = iNewLoc / DF_BLOCK_SIZE;
+		df_int4		iBlockFind;
+
+		if (iBlock >= nBlocks)
+			iBlockFind = nBlocks - 1;
+		else
+			iBlockFind = iBlock;
+		if (iBlockFind >= 0)
+		{
+			if (dfsp.iStreamBlock == DF_VTOC_EOF)
+				dfsp.iStreamBlock = -1;
+			dfsp.iStreamBlock = GetStreamBlock(dfst, iBlockFind);
+		}
+		else
+		{
+			dfsp.iStreamBlock = -1;
+		}
+		dfsp.iExtraBlocks = iBlock - iBlockFind;
+	}
+	else
+	{
+		while (iBlockOld < iBlockNew && !dfsp.iExtraBlocks)
+		{
+			df_int4 iBlock;
+			df_int4 nRead;
+
+			hr = ReadFromFileStream(dfstDataVTOC,
+						dfsp.iStreamBlock * sizeof(iBlock),
+						&iBlock,
+						sizeof(iBlock),
+						nRead);
+			if (hr)
+				return hr;
+			if (nRead != sizeof(iBlock))
+				return E_FAIL;
+			iBlock = SI4(iBlock);
+			if (iBlock == DF_VTOC_EOF)
+				dfsp.iExtraBlocks = 1;
+			else if (iBlock == DF_VTOC_FREE)
+				return E_FAIL;
+			else
+				dfsp.iStreamBlock = iBlock;
+			iBlockOld++;
+		}
+		if (iBlockOld < iBlockNew)
+			dfsp.iExtraBlocks += iBlockNew - iBlockOld;
+	}
+	dfsp.iPosition = iNewLoc;
+	if (piNewLoc)
+		*piNewLoc = iNewLoc;
+	dfsp_ = dfsp;
+	return S_OK;
+}
+
+HRESULT
+DocFileManager::Read(	DocFile_StreamPtr &dfsp,
+			void		*pvData,
+			ULONG		nBytes,
+			ULONG		&nRead)
+{
+	HRESULT hr;
+	DocFile_DirEnt dfde;
+	df_int4 iEOF;
+
+	hr = GetDirectoryEntry(dfsp.iDirectoryEntry, &dfde);
+	if (hr)
+		return hr;
+	iEOF = SI4(dfde.iFileSize);
+
+	nRead = 0;
+	if (iEOF >= FILE_LEVEL_THRESHOLD)
+	{
+		if (iEOF <= dfsp.iPosition)
+		{
+			nRead = 0;
+			return S_OK;
+		}
+		else
+		{
+			df_int4 nReadNow;
+			DF_StreamType	dfst(dfsp, dfde);
+
+			if (iEOF < dfsp.iPosition + nBytes)
+				nBytes = iEOF - dfsp.iPosition;
+			hr = ReadFromFileStream(dfst,
+						dfsp.iPosition,
+						pvData,
+						nBytes,
+						nReadNow);
+			if (hr)
+				return hr;
+			nRead = nReadNow;
+		}
+	}
+	else
+	{
+		if (dfsp.iStreamBlock == -1 &&
+		    (hr = StreamSeek(dfsp, dfsp.iPosition, 0, 0)) != 0)
+			return hr;
+		while (nBytes && !dfsp.iExtraBlocks && dfsp.iPosition < iEOF)
+		{
+			df_int4 nReadNow;
+			df_int4 iOffset = dfsp.iPosition % DF_STREAM_BLOCK_SIZE;
+			df_int4 nBytesNow = DF_STREAM_BLOCK_SIZE - iOffset;
+
+			if (nBytesNow > nBytes)
+				nBytesNow = nBytes;
+			hr = ReadFromFileStream(dfstData,
+					dfsp.iStreamBlock * DF_STREAM_BLOCK_SIZE + iOffset,
+					pvData,
+					nBytesNow,
+					nReadNow);
+			if (hr)
+				return hr;
+			if (nReadNow != nBytesNow)
+				return E_FAIL;
+			nRead += nBytesNow;
+			pvData = (char *) pvData + nBytesNow;
+			nBytes -= nBytesNow;
+			hr = StreamSeek(dfsp, nBytesNow, 0, 1);
+			if (hr)
+				return hr;
+		}
+	}
+	return S_OK;
+}
+
+HRESULT
+DocFileManager::Write(	DocFile_StreamPtr &dfsp,
+			void		const *pvData,
+			ULONG		nBytes,
+			ULONG		&nWritten)
+{
+	HRESULT hr;
+	df_int4 iVTOCBlock = -1;
+	DocFile_VTOC dfvt;
+	df_int4 iFileSize;
+	DocFile_DirEnt dfde;
+	df_int4 iEOF;
+	FILETIME ft;
+	int	iAddedBlocks = 0;
+	char	achZeroes[DF_STREAM_BLOCK_SIZE];
+
+	if (!dfsp.iPosition && !nBytes)
+	{
+		nWritten = 0;
+		return S_OK;
+	}
+	memset(achZeroes, 0, DF_STREAM_BLOCK_SIZE);
+	hr = GetDirectoryEntry(dfsp.iDirectoryEntry, &dfde);
+	if (hr)
+		return hr;
+	iEOF = SI4(dfde.iFileSize);
+	if (iEOF >= FILE_LEVEL_THRESHOLD ||
+	    dfsp.iPosition + (nBytes == (ULONG) -1 ? 0 : nBytes) >= FILE_LEVEL_THRESHOLD)
+	{
+		df_int4 nWrittenNow;
+
+		if (iEOF < FILE_LEVEL_THRESHOLD && iEOF)
+		{
+			DocFile_DirEnt dfdeOld = dfde;
+			DocFile_StreamPtr dfspOut, dfspIn;
+			char		achBuffer[FILE_LEVEL_THRESHOLD];
+			ULONG		nRead;
+
+			SI4(dfde.iVTOCPosition) = DF_VTOC_EOF;
+			SI4(dfde.iFileSize) = 0;
+			dfspOut = dfsp;
+			dfspIn = dfsp;
+			dfspOut.iPosition = 0;
+			dfspOut.iStreamBlock = -1;
+			dfspOut.iExtraBlocks = 0;
+			dfspOut.bFileStream = TRUE;
+
+			DF_StreamType	dfst(dfspOut, dfde);
+
+			hr = StreamSeek(dfspIn, 0);
+			if (hr)
+				return hr;
+			hr = Read(dfspIn, achBuffer, iEOF, nRead);
+			if (hr)
+				return hr;
+			if (nRead != iEOF)
+				return STG_E_READFAULT;
+			hr = WriteToFileStream(dfst, 0, achBuffer, iEOF, nWrittenNow);
+			if (hr)
+				return hr;
+			if (nWrittenNow != iEOF)
+				return STG_E_WRITEFAULT;
+
+			FreeDataChain(SI4(dfdeOld.iVTOCPosition));
+			SI4(dfde.iFileSize) = iEOF;
+			hr = SetDirectoryEntry(dfsp.iDirectoryEntry, &dfde);
+			if (hr)
+				return hr;
+
+			dfsp.bFileStream = TRUE;
+			dfsp.iStreamBlock = -1;
+			hr = StreamSeek(dfsp, dfsp.iPosition);
+			if (hr)
+				return hr;
+		}
+
+		DF_StreamType	dfst(dfsp, dfde);
+
+		hr = WriteToFileStream(dfst,
+					dfsp.iPosition,
+					pvData,
+					nBytes,
+					nWrittenNow);
+		if (hr)
+			return hr;
+		nWritten = nWrittenNow;
+	}
+	else
+	{
+		if (dfsp.iStreamBlock == -1 &&
+		    (hr = StreamSeek(dfsp, dfsp.iPosition, 0, 0)) != 0)
+			return hr;
+		nWritten = 0;
+		while (nBytes)
+		{
+			while (dfsp.iExtraBlocks)
+			{
+				df_int4 nWrite;
+				df_int4 iBlock = -1;
+				df_int4 iVTBNow;
+
+				iAddedBlocks = 1;
+				while (iBlock == -1)
+				{
+					df_int4 i;
+
+					iVTBNow = iLowestFreeStreamBlock / DF_VTOC_SIZE;
+					if (iVTBNow != iVTOCBlock)
+					{
+						df_int4 nRead;
+
+						hr = ReadFromFileStream(dfstDataVTOC,
+								iVTBNow * DF_BLOCK_SIZE,
+								&dfvt,
+								sizeof(dfvt),
+								nRead);
+						if (hr)
+							return hr;
+						if (nRead != sizeof(dfvt))
+							memset(&dfvt, -1, sizeof(dfvt));
+						iVTOCBlock = iVTBNow;
+					}
+					for (i = iLowestFreeStreamBlock % DF_VTOC_SIZE;
+					     i < DF_VTOC_SIZE && iBlock == -1;
+					     i++, iLowestFreeStreamBlock++)
+					{
+						df_int4 iNow = SI4(dfvt.aiBlocks[i]);
+
+						if (iNow == DF_VTOC_FREE)
+							iBlock = iLowestFreeStreamBlock;
+					}
+				}
+				SI4(dfvt.aiBlocks[iBlock % DF_VTOC_SIZE]) = DF_VTOC_EOF;
+				hr = WriteToFileStream(dfstDataVTOC,
+							iVTOCBlock * DF_BLOCK_SIZE,
+							&dfvt,
+							sizeof(dfvt),
+							nWrite);
+				if (hr)
+					return hr;
+				if (nWrite != sizeof(dfvt))
+					return E_FAIL;
+
+				if (dfsp.iStreamBlock != DF_VTOC_EOF)
+				{
+					iVTBNow = dfsp.iStreamBlock / DF_VTOC_SIZE;
+
+					if (iVTBNow != iVTOCBlock)
+					{
+						df_int4 nRead;
+
+						hr = ReadFromFileStream(dfstDataVTOC,
+								iVTBNow * DF_BLOCK_SIZE,
+								&dfvt,
+								sizeof(dfvt),
+								nRead);
+						if (hr)
+							return hr;
+						if (nRead != sizeof(dfvt))
+							return E_FAIL;
+						iVTOCBlock = iVTBNow;
+					}
+					SI4(dfvt.aiBlocks[dfsp.iStreamBlock % DF_VTOC_SIZE]) = iBlock;
+					hr = WriteToFileStream(dfstDataVTOC,
+								iVTOCBlock * DF_BLOCK_SIZE,
+								&dfvt,
+								sizeof(dfvt),
+								nWrite);
+					if (hr)
+						return hr;
+					if (nWrite != sizeof(dfvt))
+						return E_FAIL;
+				}
+				else
+				{
+					SI4(dfde.iVTOCPosition) = iBlock;
+					hr = SetDirectoryEntry(dfsp.iDirectoryEntry, &dfde);
+					if (hr)
+						return hr;
+				}
+
+				dfsp.iStreamBlock = iBlock;
+				dfsp.iExtraBlocks--;
+				WriteToFileStream(dfstData,
+						iBlock * DF_STREAM_BLOCK_SIZE,
+						achZeroes,
+						sizeof(achZeroes),
+						nWrite);
+			}
+
+			if (nBytes == (ULONG) -1)
+			{
+				nBytes = 0;
+			}
+			else
+			{
+				df_int4 nWrittenNow;
+				df_int4 iOffset = dfsp.iPosition % DF_STREAM_BLOCK_SIZE;
+				df_int4 nBytesNow = DF_STREAM_BLOCK_SIZE - iOffset;
+
+				if (nBytesNow > nBytes)
+					nBytesNow = nBytes;
+				hr = WriteToFileStream(dfstData,
+						dfsp.iStreamBlock * DF_STREAM_BLOCK_SIZE + iOffset,
+						pvData,
+						nBytesNow,
+						nWrittenNow);
+				if (hr)
+					return hr;
+				if (nWrittenNow != nBytesNow)
+					return E_FAIL;
+				nWritten += nBytesNow;
+				pvData = (char const *) pvData + nBytesNow;
+				nBytes -= nBytesNow;
+				hr = StreamSeek(dfsp, nBytesNow, 0, 1);
+				if (hr)
+					return hr;
+			}
+		}
+	}
+	if (dfsp.iPosition > iEOF)
+		SI4(dfde.iFileSize) = dfsp.iPosition;
+	GetTimeNow(ft);
+	SI4(dfde.iModifiedLow) = ft.dwLowDateTime;
+	SI4(dfde.iModifiedHigh) = ft.dwHighDateTime;
+	hr = SetDirectoryEntry(dfsp.iDirectoryEntry, &dfde);
+	if (hr)
+		return hr;
+	if (iAddedBlocks)
+	{
+		hr = GetDirectoryEntry(0, &dfde);
+		if (hr)
+			return hr;
+		iFileSize = iLowestFreeStreamBlock * DF_STREAM_BLOCK_SIZE;
+		if (SI4(dfde.iFileSize) < iFileSize)
+		{
+			SI4(dfde.iFileSize) = iFileSize;
+			hr = SetDirectoryEntry(0, &dfde);
+			if (hr)
+				return hr;
+		}
+	}
+	return S_OK;
+}
+
+HRESULT
+DocFileManager::SetStreamSize(	DocFile_StreamPtr &dfsp,
+				ULONG	iSize)
+{
+	HRESULT hr;
+	df_int4 iEOF;
+	DocFile_DirEnt dfde;
+	FILETIME	ft;
+	BOOL	bFileLevel;
+
+	hr = GetDirectoryEntry(dfsp.iDirectoryEntry, &dfde);
+	if (hr)
+		return hr;
+	iEOF = SI4(dfde.iFileSize);
+	if (iSize != iEOF)
+	{
+		DocFile_StreamPtr dfsp_ = dfsp;
+		ULONG	nWritten;
+
+		bFileLevel = (iEOF >= FILE_LEVEL_THRESHOLD);
+		dfsp_.bFileStream = bFileLevel; // Insurance
+		if (iSize)
+		{
+			hr = StreamSeek(dfsp_, iSize - 1);
+			if (hr)
+				return hr;
+		}
+		if (iSize > iEOF)
+		{
+			hr = Write(dfsp_, 0, (ULONG) -1, nWritten);
+			if (hr)
+				return hr;
+		}
+		else
+		{
+			df_int4 iChain;
+
+			if (iSize)
+			{
+				df_int4 nWritten;
+				df_int4 nRead;
+				df_int4 iVTOCPos;
+				DocFile_VTOC dfvt;
+				int	iLoc;
+				df_int4 iVTOCBlock;
+
+				iVTOCPos = dfsp_.iStreamBlock / DF_VTOC_SIZE;
+
+				if (bFileLevel)
+				{
+					iVTOCBlock = FindVTOCBlock(iVTOCPos);
+					hr = GetBlock(&dfvt, iVTOCBlock);
+					nRead = sizeof(dfvt);
+				}
+				else
+				{
+					hr = ReadFromFileStream(dfstDataVTOC,
+								iVTOCPos * DF_BLOCK_SIZE,
+								&dfvt,
+								sizeof(dfvt),
+								nRead);
+				}
+				if (hr)
+					return hr;
+				if (nRead != sizeof(dfvt))
+					return STG_E_READFAULT;
+
+				iLoc = dfsp_.iStreamBlock % DF_VTOC_SIZE;
+				iChain = SI4(dfvt.aiBlocks[iLoc]);
+				SI4(dfvt.aiBlocks[iLoc]) = DF_VTOC_EOF;
+				if (bFileLevel)
+				{
+					hr = SetBlock(&dfvt, iVTOCBlock);
+					nWritten = sizeof(dfvt);
+				}
+				else
+				{
+					hr = WriteToFileStream(dfstDataVTOC,
+								iVTOCPos * DF_BLOCK_SIZE,
+								&dfvt,
+								sizeof(dfvt),
+								nWritten);
+				}
+				if (hr)
+					return hr;
+				if (nWritten != sizeof(dfvt))
+					return STG_E_WRITEFAULT;
+			}
+			else
+			{
+				dfsp.bFileStream = dfsp_.bFileStream = FALSE;
+				iChain = SI4(dfde.iVTOCPosition);
+				SI4(dfde.iVTOCPosition) = DF_VTOC_EOF;
+				dfsp.iStreamBlock = dfsp_.iStreamBlock = DF_VTOC_EOF;
+				dfsp.iExtraBlocks = dfsp_.iPosition = dfsp.iPosition / DF_STREAM_BLOCK_SIZE;
+			}
+
+			SI4(dfde.iFileSize) = iSize;
+			GetTimeNow(ft);
+			SI4(dfde.iModifiedLow) = ft.dwLowDateTime;
+			SI4(dfde.iModifiedHigh) = ft.dwHighDateTime;
+			// FIXME - Transfer from file stream to data stream if necessary
+			hr = SetDirectoryEntry(dfsp.iDirectoryEntry, &dfde);
+			if (hr)
+				return hr;
+			if (bFileLevel)
+				hr = FreeFileChain(iChain);
+			else
+				hr = FreeDataChain(iChain);
+			if (hr)
+				return hr;
+			if (bFileLevel &&
+			    iSize < FILE_LEVEL_THRESHOLD &&
+			    iSize > 0)
+			{
+				char		achBlock[FILE_LEVEL_THRESHOLD];
+				df_int4		nRead;
+				ULONG		nWritten;
+				df_int4		iVTOCPosition = SI4(dfde.iVTOCPosition);
+
+				dfsp_.iPosition = 0;
+				dfsp_.iStreamBlock = iVTOCPosition;
+				dfsp_.iExtraBlocks = 0;
+
+				DF_StreamType dfst(dfsp_, dfde);
+
+				hr = ReadFromFileStream(dfst,
+							0,
+							achBlock,
+							iSize,
+							nRead);
+				if (hr)
+					return hr;
+				if (nRead != iSize)
+					return STG_E_READFAULT;
+				hr = FreeFileChain(iVTOCPosition);
+				if (hr)
+					return hr;
+				SI4(dfde.iVTOCPosition) = DF_VTOC_EOF;
+				dfde.iFileSize = 0;
+				dfsp_.iPosition = -1;
+				dfsp_.bFileStream = FALSE;
+				hr = SetDirectoryEntry(dfsp.iDirectoryEntry, &dfde);
+				if (hr)
+					return hr;
+				hr = StreamSeek(dfsp_, 0);
+				if (hr)
+					return hr;
+				hr = Write(dfsp_, achBlock, iSize, nWritten);
+				if (hr)
+					return hr;
+				if (nWritten != iSize)
+					return STG_E_WRITEFAULT;
+				hr = StreamSeek(dfsp_, dfsp.iPosition);
+				if (hr)
+					return hr;
+				dfsp = dfsp_;
+			}
+			else if (dfsp.iPosition > iSize)
+			{
+				hr = StreamSeek(dfsp_, dfsp.iPosition);
+				if (hr)
+					return hr;
+				dfsp = dfsp_;
+			}
+		}
+	}
+	return S_OK;
+}
+
+HRESULT
+DocFileManager::FreeFileChain(df_int4	iChain)
+{
+	DocFile_VTOC dfvt;
+	long	iVTOCPosition = -1;
+	HRESULT hr;
+	df_int4 iVTOCBlock;
+
+	while (iChain != DF_VTOC_EOF)
+	{
+		int	iLoc;
+		df_int4 iVTOCPosNow = iChain / DF_VTOC_SIZE;
+
+		if (iVTOCPosNow != iVTOCPosition)
+		{
+			if (iVTOCPosition != -1)
+			{
+				hr = SetBlock(&dfvt, iVTOCBlock);
+				if (hr)
+					return hr;
+			}
+			iVTOCBlock = FindVTOCBlock(iVTOCPosNow);
+			hr = GetBlock(&dfvt, iVTOCBlock);
+			if (hr)
+				return hr;
+			iVTOCPosition = iVTOCPosNow;
+		}
+		iLoc = iChain % DF_VTOC_SIZE;
+		pchVTOC[iChain >> 3] &= ~(1 << (iChain & 7));
+		iChain = SI4(dfvt.aiBlocks[iLoc]);
+		SI4(dfvt.aiBlocks[iLoc]) = DF_VTOC_FREE;
+	}
+	if (iVTOCPosition != -1)
+	{
+		hr = SetBlock(&dfvt, iVTOCBlock);
+		if (hr)
+			return hr;
+	}
+	return S_OK;
+}
+
+void
+DocFileManager::ShrinkDataStream(	df_int4 iVTOCPosition,
+					DocFile_VTOC &dfvt_)
+{
+	HRESULT		hr;
+	DocFile_VTOC	dfvt = dfvt_;
+	df_int4		iBlock = GetTotalStreamBlocks(dfstData) - 1;
+	df_int4		iStartBlock = iBlock;
+	int		iOffset = iBlock % DF_VTOC_SIZE;
+
+	if (iVTOCPosition * DF_VTOC_SIZE > iBlock)
+		return;
+	while (iBlock >= 0 && SI4(dfvt.aiBlocks[iOffset]) == DF_VTOC_FREE)
+	{
+		iBlock--;
+		if (iOffset)
+		{
+			iOffset--;
+		}
+		else
+		{
+			iVTOCPosition--;
+			if (iBlock >= 0)
+			{
+				df_int4 nRead;
+
+				hr = ReadFromFileStream(dfstDataVTOC,
+							iVTOCPosition * DF_BLOCK_SIZE,
+							&dfvt,
+							sizeof(dfvt),
+							nRead);
+				if (hr)
+					break;
+				if (nRead != sizeof(dfvt))
+					break;
+				iOffset = DF_VTOC_SIZE - 1;
+			}
+		}
+	}
+	if (iStartBlock != iBlock)
+	{
+		BOOL	bLinkRemoved = FALSE;
+		DocFile_StreamInfo &dfsi = adfsi[StreamTypeToIndex(dfstData)];
+		df_int4 iFileBlock = dfsi.GetBlock(iVTOCPosition + 1);
+
+		dfsi.SetTotalBlocks(iBlock + 1);
+		if (iBlock >= 0)
+		{
+			df_int4 iFileBlockLast = dfsi.GetBlock(iBlock);
+			df_int4 iVTOCBlock = FindVTOCBlock(iFileBlockLast / DF_VTOC_SIZE);
+
+			if (!GetBlock(&dfvt, iVTOCBlock))
+			{
+				SI4(dfvt.aiBlocks[iFileBlockLast % DF_VTOC_SIZE]) = DF_VTOC_EOF;
+				if (!SetBlock(&dfvt, iVTOCBlock))
+					bLinkRemoved = TRUE;
+			}
+		}
+		else if (!GetHeader())
+		{
+			dfh.iHasData = 0;
+			if (!ReleaseHeader(TRUE))
+			{
+				DocFile_DirEnt dfde;
+
+				if (!GetDirectoryEntry(0, &dfde))
+				{
+					dfde.iFileSize = 0;
+					SI4(dfde.iVTOCPosition) = DF_VTOC_EOF;
+					if (!SetDirectoryEntry(0, &dfde))
+						bLinkRemoved = TRUE;
+				}
+			}
+		}
+		if (bLinkRemoved)
+			FreeFileChain(iFileBlock);
+	}
+}
+
+HRESULT
+DocFileManager::FreeDataChain(df_int4	iChain)
+{
+	DocFile_VTOC dfvt;
+	long	iVTOCPosition = -1;
+	HRESULT hr;
+
+	while (iChain != DF_VTOC_EOF)
+	{
+		int	iLoc;
+		df_int4 iVTOCPosNow = iChain / DF_VTOC_SIZE;
+
+		if (iVTOCPosNow != iVTOCPosition)
+		{
+			df_int4 nRead;
+
+			if (iVTOCPosition != -1)
+			{
+				df_int4 nWritten;
+
+				hr = WriteToFileStream(dfstDataVTOC,
+							iVTOCPosition * DF_BLOCK_SIZE,
+							&dfvt,
+							sizeof(dfvt),
+							nWritten);
+				if (hr)
+					return hr;
+				if (nWritten != sizeof(dfvt))
+					return E_FAIL;
+				ShrinkDataStream(iVTOCPosition, dfvt);
+			}
+			hr = ReadFromFileStream(dfstDataVTOC,
+						iVTOCPosNow * DF_BLOCK_SIZE,
+						&dfvt,
+						sizeof(dfvt),
+						nRead);
+			if (hr)
+				return hr;
+			if (nRead != sizeof(dfvt))
+				return E_FAIL;
+			iVTOCPosition = iVTOCPosNow;
+		}
+		iLoc = iChain % DF_VTOC_SIZE;
+		iChain = SI4(dfvt.aiBlocks[iLoc]);
+		SI4(dfvt.aiBlocks[iLoc]) = DF_VTOC_FREE;
+	}
+	if (iVTOCPosition != -1)
+	{
+		df_int4 nWritten;
+
+		hr = WriteToFileStream(dfstDataVTOC,
+					iVTOCPosition * DF_BLOCK_SIZE,
+					&dfvt,
+					sizeof(dfvt),
+					nWritten);
+		if (hr)
+			return hr;
+		if (nWritten != sizeof(dfvt))
+			return E_FAIL;
+		ShrinkDataStream(iVTOCPosition, dfvt);
+	}
+	return S_OK;
+}
diff -uN no-docfile/dfmgr.h docfile/dfmgr.h
--- no-docfile/dfmgr.h	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dfmgr.h	2004-02-05 09:00:38.000000000 +1100
@@ -0,0 +1,268 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __DFMGR_H
+#define __DFMGR_H
+#ifndef __DOCFILE_H
+#include "docfile.h"
+#endif
+
+class	DF_RBNode;
+
+enum	DF_StreamTypeEnum
+{
+	DFST_Directory,
+	DFST_DataVTOC,
+	DFST_Data,
+	DFST_IStream
+};
+
+class	DF_StreamType
+{
+private:
+	DF_StreamTypeEnum	dfste;
+
+	DocFile_StreamPtr	&dfsp;
+	DocFile_DirEnt		&dfde;
+	df_int4			iTotalBlocks;
+
+public:
+	inline
+	DF_StreamType(	DF_StreamTypeEnum dfste_) :
+		dfste(dfste_),
+		dfsp(*(DocFile_StreamPtr *) 0),
+		dfde(*(DocFile_DirEnt *) 0)
+	{
+	}
+
+	inline
+	DF_StreamType(	DocFile_StreamPtr &dfsp_,
+			DocFile_DirEnt	&dfde_) :
+		dfste(DFST_IStream),
+		dfsp(dfsp_),
+		dfde(dfde_)
+	{
+		df_int4 iEOF = SI4(dfde.iFileSize);
+		iTotalBlocks = 0;
+
+		while (iEOF > 0)
+			iTotalBlocks++, iEOF -= DF_BLOCK_SIZE;
+	}
+
+	inline DF_StreamTypeEnum
+	GetType(void)
+	{
+		return dfste;
+	}
+
+	inline	DocFile_DirEnt &
+	GetDirEnt(void)
+	{
+		return dfde;
+	}
+
+	inline	DocFile_StreamPtr &
+	GetStreamPointer(void)
+	{
+		return dfsp;
+	}
+
+	inline	df_int4
+	GetTotalBlocks(void)
+	{
+		return iTotalBlocks;
+	}
+
+	inline	void
+	AddedBlock(void)
+	{
+		iTotalBlocks++;
+	}
+};
+
+class	DocFile_StreamInfo
+{
+private:
+	df_int4 nBlocks;
+	df_int4 nPositions;
+	unsigned char *pchBlocks;
+
+public:
+	DocFile_StreamInfo(void) :
+		nBlocks(0),
+		nPositions(0),
+		pchBlocks(0)
+	{
+	}
+
+	inline
+	~DocFile_StreamInfo(void)
+	{
+		if (pchBlocks)
+			delete [] pchBlocks;
+	}
+
+	inline	df_int4
+	GetTotalBlocks(void)
+	{
+		return nBlocks;
+	}
+
+	inline	void
+	SetTotalBlocks(df_int4 nBlocks_)
+	{
+		nBlocks = nBlocks_;
+	}
+
+	df_int4 GetBlock(	df_int4 iStreamBlock);
+	void	SetBlock(	df_int4 iStreamBlock,
+				df_int4 iFileBlock);
+};
+
+enum	DFLocType
+{
+	DFLT_Find,
+	DFLT_Create,
+	DFLT_Insert,
+	DFLT_Delete,
+	DFLT_Remove
+};
+
+#define MAX_EXTVTOCS	517
+
+class	DocFileManager :	public	IUnknown,
+				public	DocFileReferenceCounter,
+				public	DocFileInternalFunctions
+{
+private:
+	ILockBytes	*pilb;
+	DocFile_Header	dfh;
+	int		nHeaderRef;
+	BOOL		bChanged;
+	df_int4		iLowestFreeStreamBlock;
+	df_int4		aiExtVTOCs[MAX_EXTVTOCS];
+	int		nExtVTOCs;
+
+	int	iVTOCSize;
+	char	*pchVTOC;
+	DocFile_StreamInfo	adfsi[3];
+
+	int	StreamTypeToIndex(DF_StreamType &dfst);
+
+	HRESULT ExtendVTOC(void);
+	df_int4 FindVTOCBlock(	df_int4		iBlock);
+
+	df_int4 GetTotalStreamBlocks(DF_StreamType &dfst);
+	df_int4 GetStreamBlock( DF_StreamType	&dfst,
+				df_int4		iBlockNum);
+	HRESULT ExtendFileStream(DF_StreamType	&dfst,
+				df_int4		iBlockNum);
+	HRESULT ReadFromFileStream(	DF_StreamType	&dfst,
+					df_int4		iLocation,
+					void		*pvData,
+					df_int4		nBytes,
+					df_int4		&nRead);
+	HRESULT WriteToFileStream(	DF_StreamType	&dfst,
+					df_int4		iLocation,
+					void const	*pvData,
+					df_int4		nBytes,
+					df_int4		&nWritten);
+
+	HRESULT GetBlock(void		*pvData,
+			 long		iBlock);
+	HRESULT SetBlock(void const	*pvData,
+			 long		iBlock);
+	HRESULT LockBlock(long		iBlock,
+			DWORD		dwLockType);
+	HRESULT UnlockBlock(long	iBlock,
+			DWORD		dwLockType);
+	void	ShrinkDataStream(	df_int4 iVTOCPosition,
+					DocFile_VTOC &dfvt_);
+	inline	HRESULT
+	GetHeader(void)
+	{
+		if (!nHeaderRef++)
+		{
+			bChanged = FALSE;
+			return GetBlock(&dfh, -1);
+		}
+		return 0;
+	}
+
+	inline	HRESULT
+	ReleaseHeader(BOOL bChanged_)
+	{
+		if (bChanged_)
+			bChanged = TRUE;
+		if ((!nHeaderRef || !--nHeaderRef) && bChanged)
+			return SetBlock(&dfh, -1);
+		return 0;
+	}
+
+protected:
+	~DocFileManager(void);
+
+public:
+	DocFileManager(ILockBytes *pilb_);
+
+	HRESULT DF_STDCALL QueryInterface(REFIID	riid,
+			void		**ppvObj);
+	ULONG	DF_STDCALL AddRef(void) ;
+	ULONG	DF_STDCALL Release(void);
+
+	HRESULT AnnihilateEntry(	df_int4		iEntry,
+					BOOL		bSiblingsToo = FALSE);
+	df_int4 UnlinkEntry(		df_int4		iEntry);
+	HRESULT LocateChild(		df_int4		iParentLocation,
+					df_char_t const *pchName,
+					DocFile_DirEnt	&dfde,
+					df_int4		&iEntryLocation,
+					DFLocType	dflt,
+					BOOL		bStart = TRUE,
+					DF_RBNode	**ppnParent = 0);
+	HRESULT GetDirectoryEntry(	df_int4		iLocation,
+					DocFile_DirEnt	*pdfeNew);
+	HRESULT SetDirectoryEntry(	df_int4		iLocation,
+					DocFile_DirEnt	*pdfe);
+	void	SetName(		DocFile_DirEnt	*pdfe,
+					df_char_t const *pchName);
+
+	void	InitNewFile(void);
+	HRESULT InitOldFile(void);
+	void	InitDirBlock(		DocFile_DirEnt	*pdfde,
+					int		nEntries = DF_DE_PER_BLOCK);
+
+	HRESULT StreamSeek(		DocFile_StreamPtr &dfsp,
+					df_int4		iLoc,
+					df_int4		*piNewLoc = 0,
+					int		iWhence = 0);
+	HRESULT Read(			DocFile_StreamPtr &dfsp,
+					void		*pvData,
+					ULONG		nBytes,
+					ULONG		&nRead);
+	HRESULT Write(			DocFile_StreamPtr &dfsp,
+					void		const *pvData,
+					ULONG		nBytes,
+					ULONG		&nWritten);
+	HRESULT FreeDataChain(		df_int4		iChain);
+	HRESULT FreeFileChain(		df_int4		iChain);
+	HRESULT SetStreamSize(		DocFile_StreamPtr &dfsp,
+					ULONG		iSize);
+};
+#endif /* __DFMGR_H */
diff -uN no-docfile/dfo.cpp docfile/dfo.cpp
--- no-docfile/dfo.cpp	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dfo.cpp	2004-02-05 08:58:39.000000000 +1100
@@ -0,0 +1,135 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+static char const *rcsid = "$Id: dfo.cpp,v 1.4 2002/01/23 05:51:43 borgia Exp $";
+#include "docfile.h"
+#include "dfmgr.h"
+#include <string.h>
+
+DocFileObject::DocFileObject(	DocFileStorage	*pdfsParent_,
+				df_char_t const *pchName_,
+				DocFileManager	*pdfm_,
+				HRESULT		&hr,
+				df_byte		iType,
+				BOOL		bMustExist,
+				DWORD		dwMode_) :
+	pdfsParent(pdfsParent_),
+	pchName(0),
+	pdfm(pdfm_),
+	dwMode(dwMode_)
+{
+	pdfm->AddRef();
+	if (!pdfsParent)
+	{
+		iEntryNumber = 0;
+	}
+	else if (!pchName_)
+	{
+		*(char *) 0 = 0;
+	}
+	else
+	{
+		pchName = new df_char_t[df_strlen(pchName_) + 1];
+
+		pdfsParent->AddRef();
+		df_strcpy(pchName, pchName_);
+
+		hr = FindEntry(bMustExist, iType);
+		if (hr)
+			return;
+	}
+	hr = 0;
+}
+
+DocFileObject::DocFileObject(	DocFileObject	*pdfo,
+				HRESULT		&hr) :
+	pdfsParent(pdfo->pdfsParent),
+	pchName(0),
+	pdfm(pdfo->pdfm),
+	dwMode(pdfo->dwMode),
+	iEntryNumber(pdfo->iEntryNumber)
+{
+	pdfm->AddRef();
+	if (pdfsParent)
+	{
+		pchName = new df_char_t[df_strlen(pdfo->pchName) + 1];
+
+		pdfsParent->AddRef();
+		df_strcpy(pchName, pdfo->pchName);
+	}
+	hr = 0;
+}
+
+DocFileObject::~DocFileObject(void)
+{
+	pdfm->Release();
+	if (pchName)
+		delete [] pchName;
+	if (pdfsParent)
+		pdfsParent->Release();
+}
+
+HRESULT
+DocFileObject::FindEntry(BOOL bMustExist,
+			df_byte iType)
+{
+	DocFile_DirEnt	dfe;
+	HRESULT		hr;
+
+	hr = pdfm->LocateChild( pdfsParent->GetEntryNumber(),
+				pchName,
+				dfe,
+				iEntryNumber,
+				bMustExist ? DFLT_Find : DFLT_Create);
+	if (!bMustExist)
+	{
+		if (hr == STG_E_FILEALREADYEXISTS)
+		{
+			hr = 0;
+		}
+		else if (!hr)
+		{
+			dfe.iFileType = iType;
+			hr = pdfm->SetDirectoryEntry(iEntryNumber, &dfe);
+		}
+	}
+	if (!hr && dfe.iFileType != iType)
+		hr = STG_E_FILEALREADYEXISTS;
+	return hr;
+}
+
+HRESULT
+DocFileObject::Stat(	STATSTG		*pss,
+			DWORD		iStatFlags)
+{
+	DocFile_DirEnt dfde;
+	HRESULT hr = pdfm->GetDirectoryEntry(iEntryNumber, &dfde);
+	df_int4 i1;
+	df_int2 i2;
+
+	if (!hr)
+	{
+		PopulateStatStg(pss,
+				(iStatFlags & STATFLAG_NONAME) ? TRUE : FALSE,
+				dfde);
+		pss->grfMode = dwMode;
+	}
+	return hr;
+}
+
diff -uN no-docfile/dfrc.cpp docfile/dfrc.cpp
--- no-docfile/dfrc.cpp	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dfrc.cpp	2004-02-05 08:58:51.000000000 +1100
@@ -0,0 +1,46 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+static char const *rcsid = "$Id: dfrc.cpp,v 1.2 1998/06/26 01:50:04 ttsc Exp $";
+#include "docfile.h"
+
+DocFileReferenceCounter::DocFileReferenceCounter(void) :
+	nRef(1)
+{
+}
+
+DocFileReferenceCounter::~DocFileReferenceCounter(void)
+{
+}
+
+ULONG
+DocFileReferenceCounter::RCAddRef(void)
+{
+	return ++nRef;
+}
+
+ULONG
+DocFileReferenceCounter::RCRelease(void)
+{
+	ULONG	nRef_ = --nRef;
+
+	if (!nRef_)
+		delete this;
+	return nRef_;
+}
diff -uN no-docfile/dfstg.cpp docfile/dfstg.cpp
--- no-docfile/dfstg.cpp	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dfstg.cpp	2004-02-05 08:59:42.000000000 +1100
@@ -0,0 +1,529 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+static char const *rcsid = "$Id: dfstg.cpp,v 1.5 2002/01/24 02:11:18 borgia Exp $";
+#include "docfile.h"
+#include "dfmgr.h"
+#include "dfess.h"
+#include <string.h>
+#include <stdlib.h>
+
+DocFileStorage::DocFileStorage( DocFileStorage	*pdfsParent_,
+				df_char_t const *pchName_,
+				DWORD		dwMode_,
+				DocFileManager	*pdfm_,
+				HRESULT		&hr,
+				BOOL		bMustExist) :
+	DocFileObject(	pdfsParent_,
+			pchName_,
+			pdfm_,
+			hr,
+			pdfsParent_ ? DF_FT_STORAGE : DF_FT_ROOT,
+			bMustExist,
+			dwMode_)
+{
+	df_int4 iEntry = GetEntryNumber();
+	DocFile_DirEnt dfde;
+
+	pdfm->GetDirectoryEntry(iEntry, &dfde);
+}
+
+DocFileStorage::~DocFileStorage(void)
+{
+}
+
+DEFINE_REFCOUNT(DocFileStorage)
+
+HRESULT DF_STDCALL
+DocFileStorage::CreateStream(df_char_t const	*pchName,
+			DWORD		iMode,
+			DWORD		reserved1,
+			DWORD		reserved2,
+			IStream		**ppstm)
+{
+	HRESULT hr;
+
+	*ppstm = new DocFileStream(this, pchName, pdfm, iMode, FALSE, hr);
+	if (hr)
+	{
+		(*ppstm)->Release();
+		*ppstm = 0;
+	}
+	return hr;
+}
+
+
+HRESULT DF_STDCALL
+DocFileStorage::OpenStream(df_char_t const	*pchName,
+			void		*reserved1,
+			DWORD		iMode,
+			DWORD		reserved2,
+			IStream		**ppstm)
+{
+	HRESULT hr;
+
+	*ppstm = new DocFileStream(this, pchName, pdfm, iMode, TRUE, hr);
+	if (hr)
+	{
+		(*ppstm)->Release();
+		*ppstm = 0;
+	}
+	return hr;
+}
+
+
+HRESULT	 DF_STDCALL
+DocFileStorage::CreateStorage(df_char_t const *pchName,
+			DWORD		iMode,
+			DWORD		reserved1,
+			DWORD		reserved2,
+			IStorage	**ppstg)
+{
+	HRESULT hr;
+
+	*ppstg = new DocFileStorage(this, pchName, iMode, pdfm, hr, FALSE);
+	if (hr)
+	{
+		(*ppstg)->Release();
+		*ppstg = 0;
+	}
+	return hr;
+}
+
+
+HRESULT DF_STDCALL
+DocFileStorage::OpenStorage(df_char_t const	*pchName,
+			IStorage	*pstgPriority,
+			DWORD		iMode,
+			SNB		snbExclude,
+			DWORD		reserved,
+			IStorage	**ppstg)
+{
+	HRESULT hr;
+
+	*ppstg = new DocFileStorage(this, pchName, iMode, pdfm, hr, TRUE);
+	if (hr)
+	{
+		(*ppstg)->Release();
+		*ppstg = 0;
+	}
+	return hr;
+}
+
+
+HRESULT DF_STDCALL
+DocFileStorage::CopyTo( DWORD		nExclude,
+			IID const	*piidExclude,
+			SNB		snbExclude,
+			IStorage	*pstgDest)
+{
+	IEnumSTATSTG *piess = 0;
+	STATSTG ss;
+	ULONG	nFetched;
+	HRESULT hr;
+	int	i;
+	BOOL	bBanished;
+
+	if (!piidExclude || nExclude)
+	{
+		hr = EnumElements(0, 0, 0, &piess);
+		while (!hr)
+		{
+			hr = piess->Next(1, &ss, &nFetched);
+			if (!hr)
+			{
+				if (!nFetched)
+					break;
+				bBanished = FALSE;
+				if (snbExclude)
+				{
+					for (i = 0; snbExclude[i] && !bBanished; i++)
+					{
+						if (!df_stricmp(snbExclude[i], ss.pwcsName))
+							bBanished = TRUE;
+					}
+				}
+				for (i = 0; i < nExclude && !bBanished; i++)
+				{
+					if (!memcmp(&piidExclude[i],
+					    ss.type == STGTY_STREAM ?
+							&IID_IStream :
+							&IID_IStorage,
+					    sizeof(GUID)))
+						bBanished = TRUE;
+				}
+
+				if (!bBanished)
+				{
+					switch(ss.type)
+					{
+					case STGTY_STREAM:
+						{
+							IStream *pstrSrc, *pstrDst;
+								hr = OpenStream(ss.pwcsName,
+									0,
+									STGM_READ,
+									0,
+									&pstrSrc);
+							if (!hr)
+							{
+								hr = CreateStream(ss.pwcsName,
+										STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+										0,
+										0,
+										&pstrDst);
+								if (!hr)
+								{
+									ULARGE_INTEGER	uliSize;
+
+									uliSize = ss.cbSize;
+									hr = pstrSrc->CopyTo(pstrDst, uliSize, 0, 0);
+									pstrDst->Release();
+								}
+								pstrSrc->Release();
+							}
+						}
+						break;
+
+					default:
+						{
+							IStorage *pstgSrc, *pstgDst;
+
+							hr = OpenStorage(ss.pwcsName,
+									0,
+									STGM_READ,
+									0,
+									0,
+									&pstgSrc);
+							if (!hr)
+							{
+								hr = pstgDest->CreateStorage(ss.pwcsName,
+												STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+												0,
+												0,
+												&pstgDst);
+								if (!hr)
+								{
+									hr = pstgSrc->CopyTo(0, 0, 0, pstgDst);
+									pstgDst->Release();
+								}
+								pstgSrc->Release();
+							}
+						}
+						break;
+					}
+					if (!hr)
+						hr = pstgDest->SetElementTimes(ss.pwcsName,
+										&ss.ctime,
+										&ss.atime,
+										&ss.mtime);
+				}
+				free(ss.pwcsName);
+			}
+		}
+		if (piess)
+			piess->Release();
+	}
+	else
+	{
+		hr = 0;
+	}
+	if (!hr)
+	{
+		hr = Stat(&ss, STATFLAG_NONAME);
+
+		if (!hr)
+		{
+			hr = pstgDest->SetStateBits(ss.grfStateBits, (df_uint4) -1);
+			if (!hr)
+			{
+				hr = pstgDest->SetClass(ss.clsid);
+			}
+		}
+	}
+	return hr;
+}
+
+
+HRESULT DF_STDCALL
+DocFileStorage::MoveElementTo(df_char_t const *pchOldName,
+			IStorage	*pstgDest,
+			df_char_t const *pchNewName,
+			DWORD		iFlags)
+{
+	HRESULT hr;
+	df_int4 iEntry;
+	DocFile_DirEnt dfde;
+	df_int4 iParent = GetEntryNumber();
+
+	hr = pdfm->LocateChild( iParent,
+				pchOldName,
+				dfde,
+				iEntry,
+				DFLT_Find);
+	if (!hr)
+	{
+		switch(dfde.iFileType)
+		{
+		case DF_FT_STREAM:
+			{
+				IStream *pstrSrc, *pstrDst;
+
+				hr = OpenStream(pchOldName,
+						0,
+						STGM_READ,
+						0,
+						&pstrSrc);
+				if (!hr)
+				{
+					hr = CreateStream(pchNewName,
+							STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+							0,
+							0,
+							&pstrDst);
+					if (!hr)
+					{
+						ULARGE_INTEGER	uliSize;
+
+						uliSize.u.LowPart = SI4(dfde.iFileSize);
+						uliSize.u.HighPart = 0;
+						hr = pstrSrc->CopyTo(pstrDst, uliSize, 0, 0);
+						pstrDst->Release();
+					}
+					pstrSrc->Release();
+				}
+			}
+			break;
+
+		default:
+			{
+				IStorage *pstgSrc, *pstgDst;
+
+				hr = OpenStorage(pchOldName,
+						0,
+						STGM_READ,
+						0,
+						0,
+						&pstgSrc);
+				if (!hr)
+				{
+					hr = pstgDest->CreateStorage(pchNewName,
+									STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+									0,
+									0,
+									&pstgDst);
+					if (!hr)
+					{
+						hr = pstgSrc->CopyTo(0, 0, 0, pstgDst);
+						pstgDst->Release();
+					}
+					pstgSrc->Release();
+				}
+			}
+			break;
+		}
+		if (!hr && iFlags == STGMOVE_MOVE)
+			hr = DestroyElement(pchOldName);
+	}
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileStorage::Commit( DWORD		iCommitFlags)
+{
+	return 0;
+}
+
+HRESULT DF_STDCALL
+DocFileStorage::Revert(void)
+{
+	return E_FAIL;
+}
+
+HRESULT DF_STDCALL
+DocFileStorage::EnumElements(DWORD	reserved1,
+			void		*reserved2,
+			DWORD		reserved3,
+			IEnumSTATSTG	**ppiess)
+{
+	HRESULT hr = S_OK;
+
+	*ppiess = new DocFileEnumStatStg(this, hr);
+	if (hr)
+	{
+		(*ppiess)->Release();
+		*ppiess = 0;
+	}
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileStorage::DestroyElement(df_char_t const *pchName)
+{
+	HRESULT hr;
+	df_int4 iEntry;
+	DocFile_DirEnt dfde;
+
+	hr = pdfm->LocateChild( GetEntryNumber(),
+				pchName,
+				dfde,
+				iEntry,
+				DFLT_Delete);
+	if (!hr)
+		hr = pdfm->AnnihilateEntry(iEntry);
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileStorage::RenameElement(df_char_t const *pchOldName,
+			df_char_t const *pchNewName)
+{
+	HRESULT hr;
+	df_int4 iEntry;
+	DocFile_DirEnt dfde;
+	df_int4 iParent = GetEntryNumber();
+
+	hr = pdfm->LocateChild( iParent,
+				pchOldName,
+				dfde,
+				iEntry,
+				DFLT_Find);
+	if (!hr)
+	{
+		hr = pdfm->LocateChild( iParent,
+					pchOldName,
+					dfde,
+					iEntry,
+					DFLT_Remove);
+		if (!hr)
+		{
+			pdfm->SetName(&dfde, pchNewName);
+			hr = pdfm->SetDirectoryEntry(iEntry, &dfde);
+
+			if (!hr)
+			{
+				hr = pdfm->LocateChild( iParent,
+							pchNewName,
+							dfde,
+							iEntry,
+							DFLT_Insert);
+			}
+		}
+	}
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileStorage::SetElementTimes(df_char_t const *lpszName,
+			FILETIME const	*pftCreated,
+			FILETIME const	*,
+			FILETIME const	*pftModified)
+{
+	DocFile_DirEnt	dfde;
+	df_int4		iLocation;
+	HRESULT		hr;
+
+	if (pftModified || pftCreated)
+	{
+		hr = pdfm->LocateChild( GetEntryNumber(),
+					lpszName,
+					dfde,
+					iLocation,
+					DFLT_Find);
+		if (!hr)
+		{
+			if (pftCreated)
+			{
+				SI4(dfde.iCreatedLow) = pftCreated->dwLowDateTime;
+				SI4(dfde.iCreatedHigh) = pftCreated->dwHighDateTime;
+			}
+			if (pftModified)
+			{
+				SI4(dfde.iModifiedLow) = pftModified->dwLowDateTime;
+				SI4(dfde.iModifiedHigh) = pftModified->dwHighDateTime;
+			}
+			hr = pdfm->SetDirectoryEntry(iLocation, &dfde);
+		}
+	}
+	else
+	{
+		hr = S_OK;
+	}
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileStorage::SetClass(REFCLSID	clsid)
+{
+	HRESULT hr;
+	df_int4 iEntry = GetEntryNumber();
+	DocFile_DirEnt dfe;
+
+	hr = pdfm->GetDirectoryEntry(iEntry, &dfe);
+	if (!hr)
+	{
+		struct
+		{
+			df_int4 i1;
+			df_int2 i2;
+		} ints;
+
+		SI4(ints.i1) = clsid.Data1;
+		memcpy(dfe.achClassID, &ints.i1, 4);
+		SI2(ints.i2) = clsid.Data2;
+		memcpy(dfe.achClassID + 4, &ints.i2, 2);
+		SI2(ints.i2) = clsid.Data3;
+		memcpy(dfe.achClassID + 6, &ints.i2, 2);
+		memcpy(dfe.achClassID + 8, clsid.Data4, 8);
+		hr = pdfm->SetDirectoryEntry(iEntry, &dfe);
+	}
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileStorage::SetStateBits(DWORD	iStateBits,
+			DWORD		giMask)
+{
+	HRESULT hr;
+	DocFile_DirEnt dfe;
+	df_int4 iEntry = GetEntryNumber();
+
+	hr = pdfm->GetDirectoryEntry(iEntry, &dfe);
+	if (!hr)
+	{
+#ifdef DF_INTEL_BYTE_ORDER
+		df_int4 &si = dfe.iStateBits;
+#else
+		__CV_SI4	si(dfe.iStateBits);
+#endif
+
+		si = (si & ~giMask) | iStateBits;
+		hr = pdfm->SetDirectoryEntry(iEntry, &dfe);
+	}
+	return hr;
+}
+
+HRESULT DF_STDCALL
+DocFileStorage::Stat(STATSTG		*pstatstg,
+			DWORD		iStatFlags)
+{
+	return DocFileObject::Stat(pstatstg, iStatFlags);
+}
+
+
diff -uN no-docfile/dfstream.cpp docfile/dfstream.cpp
--- no-docfile/dfstream.cpp	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dfstream.cpp	2004-02-05 08:59:48.000000000 +1100
@@ -0,0 +1,215 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+static char const *rcsid = "$Id: dfstream.cpp,v 1.7 1999/01/20 05:05:05 ttsc Exp $";
+#include "docfile.h"
+#include "dfmgr.h"
+
+DocFileStream::DocFileStream(	DocFileStorage	*pdfsParent_,
+				char const	*pchName_,
+				DocFileManager	*pdfm_,
+				DWORD		dwMode_,
+				BOOL		bMustExist,
+				HRESULT		&hr) :
+	DocFileObject(	pdfsParent_,
+			pchName_,
+			pdfm_,
+			hr,
+			DF_FT_STREAM,
+			bMustExist,
+			dwMode_)
+{
+	if (!hr)
+	{
+		dfsp.iDirectoryEntry = GetEntryNumber();
+		pdfm->StreamSeek(dfsp, 0);
+	}
+}
+
+DocFileStream::DocFileStream(	DocFileStream	*pstr,
+				HRESULT		&hr) :
+	DocFileObject(	pstr,
+			hr),
+	dfsp(pstr->dfsp)
+{
+	dfsp = pstr->dfsp;
+}
+
+DocFileStream::~DocFileStream(void)
+{
+}
+
+DEFINE_REFCOUNT(DocFileStream)
+
+HRESULT
+DocFileStream::Read(	VOID		*pvData,
+			ULONG		nBytes,
+			ULONG		*pnRead)
+{
+	HRESULT	hr;
+	ULONG	nRead;
+
+	hr = pdfm->Read(dfsp, pvData, nBytes, nRead);
+	if (!hr && pnRead)
+		*pnRead = nRead;
+	return hr;
+}
+
+HRESULT
+DocFileStream::Write(	VOID const	*pvData,
+			ULONG		nBytes,
+			ULONG		*pnWritten)
+{
+	HRESULT	hr;
+	ULONG	nWritten;
+
+	hr = pdfm->Write(dfsp, pvData, nBytes, nWritten);
+	if (!hr && pnWritten)
+		*pnWritten = nWritten;
+	return hr;
+}
+
+HRESULT
+DocFileStream::Seek(	LARGE_INTEGER 	iMove,
+			DWORD 		dwOrigin,
+			ULARGE_INTEGER	*piNewPosition)
+{
+	HRESULT	hr;
+	df_int4	iLoc;
+	df_int4	iNew;
+
+	hr = Translate(&iLoc, &iMove);
+	if (!hr)
+	{
+		hr = pdfm->StreamSeek(dfsp, iLoc, &iNew, dwOrigin);
+		if (!hr)
+			hr = Translate(piNewPosition, iNew);
+	}
+	return hr;
+}
+
+HRESULT
+DocFileStream::SetSize(ULARGE_INTEGER	iNewSize)
+{
+	HRESULT	hr;
+	df_int4	iSize;
+
+	hr = Translate(&iSize, &iNewSize);
+	if (!hr)
+		hr = pdfm->SetStreamSize(dfsp, iSize);
+	return hr;
+}
+
+HRESULT
+DocFileStream::CopyTo(	IStream		*pstm,
+			ULARGE_INTEGER	nBytes_,
+			ULARGE_INTEGER	*pnRead,
+			ULARGE_INTEGER	*pnWritten)
+{
+	HRESULT	hr = S_OK;
+	df_int4	nBytes;
+	char	achBuffer[DF_BLOCK_SIZE];
+	df_int4	nRead = 0;
+	df_int4	nWritten = 0;
+
+	hr = Translate(&nBytes, &nBytes_);
+	if (hr)
+		return hr;
+	while (nBytes)
+	{
+		long	nBytesNow = nBytes;
+		ULONG	nReadNow;
+		ULONG	nWrittenNow;
+
+		if (DF_BLOCK_SIZE < nBytesNow)
+			nBytesNow = DF_BLOCK_SIZE;
+		hr = pdfm->Read(dfsp, achBuffer, nBytesNow, nReadNow);
+		if (hr)
+			break;
+		if (!nReadNow)
+			break;
+		nRead += nReadNow;
+		hr = pstm->Write(achBuffer, nRead, &nWrittenNow);
+		if (hr)
+			break;
+		if (nReadNow != nWrittenNow)
+		{
+			hr = E_FAIL;
+			break;
+		}
+		nWritten += nWrittenNow;
+		nBytes -= nBytesNow;
+	}
+	if (pnRead)
+		Translate(pnRead, nRead);
+	if (pnWritten)
+		Translate(pnWritten, nWritten);
+	return hr;
+}
+
+HRESULT
+DocFileStream::Commit(	DWORD		iCommitFlags)
+{
+	return S_OK;
+}
+
+HRESULT
+DocFileStream::Revert(void)
+{
+	return S_OK;
+}
+
+HRESULT
+DocFileStream::LockRegion(ULARGE_INTEGER iOffset,
+			ULARGE_INTEGER	nBytes,
+			DWORD		dwLockType)
+{
+	return S_OK;
+}
+
+HRESULT
+DocFileStream::UnlockRegion(ULARGE_INTEGER iOffset,
+			ULARGE_INTEGER	nBytes,
+			DWORD		dwLockType)
+{
+	return S_OK;
+}
+
+HRESULT
+DocFileStream::Stat(	STATSTG		*pss,
+			DWORD		iStatFlags)
+{
+	return DocFileObject::Stat(pss, iStatFlags);
+}
+
+HRESULT
+DocFileStream::Clone(	IStream		**ppstm)
+{
+	HRESULT	hr = S_OK;
+
+	*ppstm = new DocFileStream(this, hr);
+	if (hr)
+	{
+		(*ppstm)->Release();
+		*ppstm = 0;
+	}
+	return hr;
+}
+
+
diff -uN no-docfile/dftypes.h docfile/dftypes.h
--- no-docfile/dftypes.h	1970-01-01 10:00:00.000000000 +1000
+++ docfile/dftypes.h	2004-02-05 09:00:50.000000000 +1100
@@ -0,0 +1,112 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __DFTYPES_H
+#define __DFTYPES_H
+
+#if defined(__alpha__) && defined(__osf__)
+#define	BITS_64
+#define	DF_INTEL_BYTE_ORDER
+#else
+#define BITS_32
+#endif
+
+#ifdef BITS_64
+typedef unsigned	df_uint4;
+typedef int		df_int4;
+typedef unsigned short	df_uint2;
+typedef short		df_int2;
+typedef unsigned char	df_byte;
+typedef short		df_char;
+#else
+typedef unsigned long	df_uint4;
+typedef long		df_int4;
+typedef unsigned short	df_uint2;
+typedef short		df_int2;
+typedef unsigned char	df_byte;
+typedef short		df_char;	/* Actually wchar_t */
+#endif
+
+
+#ifndef __WINDOWS_H
+#ifdef BITS_64
+typedef long LONGLONG;
+typedef unsigned long DWORDLONG;
+#else
+typedef long long	LONGLONG;
+typedef unsigned long long DWORDLONG;
+#endif
+
+typedef int		BOOL;
+typedef df_uint4	DWORD;
+typedef df_uint4	ULONG;
+typedef df_int4		LONG;
+typedef df_uint2	WORD;
+typedef df_byte		BYTE;
+typedef df_uint4	HRESULT;
+typedef void		VOID;		/* Duuuh */
+typedef char		*LPSTR;
+#define TRUE		1
+#define FALSE		0
+
+typedef union	tagULARGE_INTEGER
+{
+	struct
+	{
+#ifdef DF_INTEL_BYTE_ORDER
+		DWORD	LowPart;
+		DWORD	HighPart;
+#else
+		DWORD	HighPart;
+		DWORD	LowPart;
+#endif
+	} u;
+	DWORDLONG	QuadPart;
+} ULARGE_INTEGER;
+
+
+typedef union	tagLARGE_INTEGER
+{
+	struct
+	{
+#ifdef DF_INTEL_BYTE_ORDER
+		DWORD	LowPart;
+		LONG	HighPart;
+#else
+		LONG	HighPart;
+		DWORD	LowPart;
+#endif
+	} u;
+	LONGLONG	QuadPart;
+} LARGE_INTEGER;
+
+typedef struct tagFILETIME
+{
+	DWORD dwLowDateTime;
+	DWORD dwHighDateTime;
+} FILETIME;
+
+
+#ifndef __GUID_H
+#include "guid.h"
+#endif /* __GUID_H */
+
+#endif /* __WINDOWS_H */
+#endif /* __DFTYPES_H */
+
diff -uN no-docfile/docfile.cpp docfile/docfile.cpp
--- no-docfile/docfile.cpp	1970-01-01 10:00:00.000000000 +1000
+++ docfile/docfile.cpp	2004-02-05 08:59:58.000000000 +1100
@@ -0,0 +1,143 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+static char const *rcsid = "$Id: docfile.cpp,v 1.4 1999/01/20 02:58:09 troy Exp $";
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include "docfile.h"
+#include "dfmgr.h"
+
+HRESULT DF_STDCALL
+StgIsStorageFile(	char const	*pchName)
+{
+	int	fd;
+	unsigned char	achMagic[4];
+
+	fd = open(pchName, O_RDONLY);
+	if (fd == -1)
+		return E_FAIL;
+	memset(achMagic, 0, sizeof(achMagic));
+	read(fd, achMagic, sizeof(achMagic));
+	close(fd);
+	return (achMagic[0] == 0xd0 &&
+		achMagic[1] == 0xcf &&
+		achMagic[2] == 0x11 &&
+		achMagic[3] == 0xe0) ? S_OK : E_FAIL;
+}
+
+HRESULT DF_STDCALL
+StgCreateDocfile(	char const	*pchName,
+			DWORD		iMode,
+			DWORD		reserved,
+			IStorage	**ppstgOpen)
+{
+	HRESULT hr;
+	ILockBytes *pilb;
+
+	iMode |= STGM_CREATE;
+	pilb = new FileLockBytes(pchName, iMode, hr);
+	if (hr)
+	{
+		pilb->Release();
+		return hr;
+	}
+	hr = StgCreateDocfileOnILockBytes(pilb, iMode, 0, ppstgOpen);
+	pilb->Release();
+	return hr;
+}
+
+HRESULT DF_STDCALL
+StgOpenStorage( const char	*pchName,
+		IStorage	*pstgPriority,
+		DWORD		iMode,
+		SNB		snbExclude,
+		DWORD		reserved,
+		IStorage	**ppstgOpen)
+{
+	HRESULT hr;
+	ILockBytes *pilb;
+
+	pilb = new FileLockBytes(pchName, iMode, hr);
+	if (hr)
+	{
+		pilb->Release();
+		return hr;
+	}
+	hr = StgOpenStorageOnILockBytes(pilb,
+					pstgPriority,
+					iMode,
+					snbExclude,
+					0,
+					ppstgOpen);
+	pilb->Release();
+	return hr;
+}
+
+HRESULT DF_STDCALL
+StgCreateDocfileOnILockBytes(ILockBytes *plkbyt,
+			DWORD		iMode,
+			DWORD		reserved,
+			IStorage	**ppstgOpen)
+{
+	DocFileManager	*pdfm;
+	HRESULT		hr;
+
+	iMode |= STGM_CREATE;
+	pdfm = new DocFileManager(plkbyt);
+	pdfm->InitNewFile();
+	*ppstgOpen = new DocFileStorage(0, 0, iMode, pdfm, hr, FALSE);
+	pdfm->Release();
+	if (hr)
+	{
+		(*ppstgOpen)->Release();
+		*ppstgOpen = 0;
+	}
+	return hr;
+}
+
+HRESULT DF_STDCALL
+StgOpenStorageOnILockBytes(	ILockBytes	*plkbyt,
+				IStorage	*pStgPriority,
+				DWORD		iMode,
+				SNB		snbExclude,
+				DWORD		reserved,
+				IStorage	**ppstgOpen)
+{
+	DocFileManager	*pdfm;
+	HRESULT		hr;
+
+	iMode |= STGM_CREATE;
+	pdfm = new DocFileManager(plkbyt);
+	hr = pdfm->InitOldFile();
+	if (hr)
+	{
+		pdfm->Release();
+		return hr;
+	}
+	*ppstgOpen = new DocFileStorage(0, 0, iMode, pdfm, hr, FALSE);
+	pdfm->Release();
+	if (hr)
+	{
+		(*ppstgOpen)->Release();
+		*ppstgOpen = 0;
+	}
+	return hr;
+}
diff -uN no-docfile/docfile.h docfile/docfile.h
--- no-docfile/docfile.h	1970-01-01 10:00:00.000000000 +1000
+++ docfile/docfile.h	2004-02-05 09:13:13.000000000 +1100
@@ -0,0 +1,553 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __DOCFILE_H
+#define __DOCFILE_H
+
+#define DF_STDCALL
+#ifndef __STORAGE_H
+#include "storage.h"
+#endif
+typedef		char	df_char_t;
+#define df_strlen	strlen
+#define df_strcpy	strcpy
+#define df_stricmp	stricmp
+
+#ifndef __DFCONV_H
+#include "dfconv.h"
+#endif
+
+
+#if (defined(__sun__) || defined(_AIX) || defined(linux) || (defined(__alpha__) && defined(__osf__)))&& !defined(stricmp)
+extern "C" int strcasecmp(char const *, char const *);
+#define stricmp strcasecmp
+#endif
+
+
+
+#define DF_EXT_VTOC		-4
+#define DF_VTOC_VTOC		-3
+#define DF_VTOC_EOF		-2
+#define DF_VTOC_FREE		-1
+#define DF_NAMELEN	0x20	/* Maximum entry name length - 31 characters plus
+				   a NUL terminator */
+
+#define DF_FT_STORAGE		1
+#define DF_FT_STREAM		2
+#define DF_FT_LOCKBYTES		3	// Not used -- How the bloody hell did I manage
+#define DF_FT_PROPERTY		4	// Not Used -- to figure these two out?
+#define DF_FT_ROOT		5
+
+#define DF_BLOCK_SIZE		0x200
+#define DF_VTOC_SIZE		0x80
+#define DF_DE_PER_BLOCK		4
+#define DF_STREAM_BLOCK_SIZE	0x40
+
+/* A DocFile is divided into blocks of 512 bytes.
+ * The first block contains the header.
+ *
+ * The file header contains The first 109 entries in the VTOC of VTOCs.
+ *
+ * Each block pointed to by a VTOC of VTOCs contains a VTOC, which
+ * includes block chains - just like FAT. This is a somewhat poor
+ * design for the following reasons:
+ *
+ *	1. FAT was a poor file system design to begin with, and
+ *	   has long been known to be horrendously inefficient
+ *	   for day to day operations.
+ *
+ *	2. The problem is compounded here, since the file
+ *	   level streams are generally *not* read sequentially.
+ *	   This means that a significant percentage of reads
+ *	   require seeking from the start of the chain.
+ *
+ * Data chains also contain an internal VTOC. The block size for
+ * the standard VTOC is 512. The block size for the internal VTOC
+ * is 64.
+ *
+ * Now, the 109 blocks in the VTOC of VTOCs allows for files of
+ * up to around 7MB. So what do you think happens if that's
+ * exceeded? Well, there's an entry in the header block which
+ * points to the first block used as additional storage for
+ * the VTOC of VTOCs.
+ *
+ * Now we can get up to around 15MB. Now, guess how the file
+ * format adds in another block to the VTOC of VTOCs. Come on,
+ * it's no big surprise. That's right - the last entry in each
+ * block extending the VTOC of VTOCs is, you guessed it, the
+ * block number of the next block containing an extension to
+ * the VTOC of VTOCs. The VTOC of VTOCs is chained!!!!
+ *
+ * So, to review:
+ *
+ * 1. If you are using a FAT file system, the location of
+ *    your file's blocks is stored in chains.
+ *
+ * 2. At the abstract level, the file contains a VTOC of VTOCs,
+ *    which is stored in the most inefficient possible format for
+ *    random access - a chain (AKA list).
+ *
+ * 3. The VTOC of VTOCs contains descriptions of three file level
+ *    streams:
+ *
+ *    a. The Directory stream
+ *    b. The Data stream
+ *    c. The Data VTOC stream
+ *
+ *    These are, of course, represented as chains.
+ *
+ * 4. The Data VTOC contains data describing the chains of blocks
+ *    within the Data stream.
+ *
+ * That's right - we have a total of four levels of block chains!
+ *
+ * Now, is that complicated enough for you? No? OK, there's another
+ * complication. If an individual stream (ie. an IStream) reaches
+ * 4096 bytes in size, it gets moved from the Data Stream to
+ * a new file level stream. Now, if the stream then gets truncated
+ * back to less than 4096 bytes, it returns to the data stream.
+ *
+ * The effect of using this format can be seen very easily. Pick
+ * an arbitrary application with a grid data representation that
+ * can export to both Lotus 123 and Excel 5 or higher. Export
+ * a large file to Lotus 123 and time it. Export the same thing
+ * to Excel 5 and time that. The difference is the inefficiency
+ * of the Microsoft DocFile format.
+ *
+ */
+#define TOTAL_SIMPLE_VTOCS	109
+
+struct	DocFile_Header
+{
+	df_byte iMagic1;	/* 0xd0 */
+	df_byte iMagic2;	/* 0xcf */
+	df_byte iMagic3;	/* 0x11 */
+	df_byte iMagic4;	/* 0xe0 - Spells D0CF11E0, or DocFile */
+	df_byte iMagic5;	/* 161	(igi upside down) */
+	df_byte iMagic6;	/* 177	(lli upside down - see below */
+	df_byte iMagic7;	/* 26 (gz upside down) */
+	df_byte iMagic8;	/* 225 (szz upside down) - see below */
+	df_int4 aiUnknown1[4];
+	df_int4 iVersion;	/* DocFile Version - 0x03003E	*/
+	df_int4 aiUnknown2[4];
+	df_int4 nVTOCs;		/* Number of VTOCs */
+	df_int4 iFirstDirBlock; /* First Directory Block */
+	df_int4 aiUnknown3[2];
+	df_int4 iFirstDataVTOC; /* First data VTOC block */
+	df_int4 iHasData;	/* 1 if there is data in the file - yes, this is important*/
+	df_int4 iExtendedVTOC;	/* Extended VTOC location */
+	df_int4 iExtendedVTOCSize; /* Size of extended VTOC (+1?) */
+	df_int4 aiVTOCofVTOCs[TOTAL_SIMPLE_VTOCS];
+};
+
+struct	DocFile_VTOC
+{
+	df_int4 aiBlocks[DF_VTOC_SIZE];
+};
+
+
+/* The meaning of the magic numbers
+ *
+ * 0xd0cf11e0 is DocFile with a zero on the end (sort of)
+ *
+ * If you key 177161 into a calculator, then turn the calculator
+ * upside down, you get igilli, which may be a reference to
+ * somebody's name, or to the Hebrew word for "angel".
+ *
+ * If you key 26225 into a calculator, then turn it upside down, you
+ * get szzgz. Microsoft has a tradition of creating nonsense words
+ * using the letters s, g, z and y. We think szzgz may be one of the
+ * Microsoft placeholder variables, along the lines of foo, bar and baz.
+ * Alternatively, it could be 22526, which would be gzszz.
+ */
+
+struct	DocFile_DirEnt
+{
+	df_char achEntryName[DF_NAMELEN];	/* Entry Name */
+	df_int2 iNameLen;			/* Name length in bytes, including NUL terminator */
+	df_byte iFileType;			/* Entry type */
+	df_byte iColour;			/* 1 = Black, 0 = Red */
+	df_int4 iLeftSibling;			/* Next Left Sibling Entry - See below */
+	df_int4 iRightSibling;			/* Next Right Sibling Entry */
+	df_int4 iFirstChild;			/* First Child Entry */
+	df_byte achClassID[16];			/* Class ID */
+	df_int4 iStateBits;			/* [GS]etStateBits value */
+	df_int4 iCreatedLow;			/* Low DWORD of creation time */
+	df_int4 iCreatedHigh;			/* High DWORD of creation time */
+	df_int4 iModifiedLow;			/* Low DWORD of modification time */
+	df_int4 iModifiedHigh;			/* High DWORD of modification time */
+	df_int4 iVTOCPosition;			/* VTOC Position */
+	df_int4 iFileSize;			/* Size of the stream */
+	df_int4 iZero;				/* We think this is part of the 64 bit stream size - must be 0 */
+};
+
+/* Siblings
+ * ========
+ *
+ * Siblings are stored in an obscure but incredibly elegant
+ * data structure called a red-black tree. This is generally
+ * defined as a 2-3-4 tree stored in a binary tree.
+ *
+ * A red-black tree can always be balanced very easily. The rules
+ * for a red-black tree are as follows:
+ *
+ *	1. The root node is always black.
+ *	2. The parent of a red node is always black.
+ *
+ * There is a Java demo of red-black trees at:
+ *
+ *	http://langevin.usc.edu/BST/RedBlackTree-Example.html
+ *
+ * This demo is an excellent tool for learning how red-black
+ * trees work, without having to go through the process of
+ * learning how they were derived.
+ *
+ * Within the tree, elements are ordered by the length of the
+ * name and within that, ASCII order by name. This causes the
+ * apparently bizarre reordering you see when you use dfview.
+ *
+ * This is a somewhat bizarre choice. It suggests that the
+ * designer of the DocFile format was trying to optimise
+ * searching through the directory entries. However searching
+ * through directory entries is a relatively rare operation.
+ * Reading and seeking within a stream are much more common
+ * operations, especially within the file level streams, yet
+ * these use the horrendously inefficient FAT chains.
+ *
+ * This suggests that the designer was probably somebody
+ * fresh out of university, who had some basic knowledge of
+ * basic data structures, but little knowledge of anything
+ * more practical. It is bizarre to attempt to optimise
+ * directory searches while not using a more efficient file
+ * block locating system than FAT (seedling/sapling/tree
+ * would result in a massive improvement - in fact we have
+ * an alternative to DocFiles that we use internally that
+ * uses seedling/sapling/tree and *is* far more efficient).
+ *
+ * It is worth noting that the MS implementation of red-black
+ * trees is incorrect (I can tell you're surprised) and
+ * actually causes more operations to occur than are really
+ * needed. Fortunately the fact that our implementation is
+ * correct will not cause any problems - the MS implementation
+ * still appears to cause the tree to satisfy the rules, albeit
+ * a sequence of the same insertions in the different
+ * implementations may result in a different, and possibly
+ * deeper (but never shallower) tree.
+ */
+
+
+
+class	DocFileManager;
+class	DocFileInternalFunctions
+{
+public:
+	static	HRESULT TranslateError(void);
+
+	HRESULT Translate(	ULARGE_INTEGER	*piULARGE,
+				LONG		i);
+	HRESULT Translate(	LONG		*pi,
+				ULARGE_INTEGER const *piULARGE);
+	HRESULT Translate(	LARGE_INTEGER	*piULARGE,
+				LONG		i);
+	HRESULT Translate(	LONG		*pi,
+				LARGE_INTEGER const *piULARGE);
+	HRESULT Translate(	FILETIME	*pft,
+				LONG		i);
+	HRESULT Translate(	LONG		*pi,
+				FILETIME const	*pft);
+	void	GetTimeNow(	FILETIME	&ft);
+	void	PopulateStatStg(STATSTG *pss,
+				BOOL	bIncludeName,
+				DocFile_DirEnt &dfde);
+	void	GetName(	DocFile_DirEnt	*pdfe,
+				df_char_t	*pchName);
+};
+
+class	DocFileReferenceCounter
+{
+private:
+	ULONG	nRef;
+
+protected:
+	virtual ~DocFileReferenceCounter(void);
+
+public:
+	DocFileReferenceCounter(void);
+
+	ULONG	RCAddRef(void);
+	ULONG	RCRelease(void);
+};
+
+#define DEFINE_REFCOUNT(x)	ULONG DF_STDCALL x::AddRef(void) { return RCAddRef(); } \
+				ULONG DF_STDCALL x::Release(void) { return RCRelease(); } \
+				HRESULT DF_STDCALL x::QueryInterface(REFIID, void **) { return E_FAIL; }
+
+#define DF_FLB_BUFFERS	8
+
+struct	DF_Cache
+{
+	df_int4		iBlock;
+	df_int4		iLastUsed;
+	char		achData[DF_BLOCK_SIZE];
+	BOOL		bDirty;
+
+	DF_Cache(void) :
+		iBlock(-1),
+		iLastUsed(-1)
+	{
+	}
+};
+
+class	FileLockBytes : public ILockBytes, public DocFileReferenceCounter, public DocFileInternalFunctions
+{
+private:
+	DF_Cache	aCache[DF_FLB_BUFFERS];
+	df_int4		iSequence;
+	char		*pchFileName;
+	DWORD		dwMode;
+	int		fd;
+
+	HRESULT MoveTo( long iOffset);
+
+	HRESULT GetCache(df_int4 iBlock, int &iCache);
+	void	Flush(int iCache);
+
+protected:
+	~FileLockBytes(void);
+
+public:
+	FileLockBytes(	char const	*pchFileName_,
+			DWORD		dwMode_,
+			HRESULT		&hr);
+
+	HRESULT DF_STDCALL QueryInterface(REFIID	riid,
+			void		**ppvObj);
+	ULONG	DF_STDCALL AddRef(void) ;
+	ULONG	DF_STDCALL Release(void);
+
+	HRESULT DF_STDCALL ReadAt(	ULARGE_INTEGER	iOffset,
+			VOID		*pvData,
+			ULONG		nBytes,
+			ULONG		*pnRead);
+	HRESULT DF_STDCALL WriteAt(ULARGE_INTEGER	iOffset,
+			VOID const	*pvData,
+			ULONG		nBytes,
+			ULONG		*pnWritten);
+	HRESULT DF_STDCALL Flush(void);
+	HRESULT DF_STDCALL SetSize(ULARGE_INTEGER	nBytes);
+	HRESULT DF_STDCALL LockRegion(ULARGE_INTEGER iOffset,
+			ULARGE_INTEGER	nBytes,
+			DWORD		dwLockType);
+	HRESULT DF_STDCALL UnlockRegion(ULARGE_INTEGER iOffset,
+			ULARGE_INTEGER	nBytes,
+			DWORD		dwLockType);
+	HRESULT DF_STDCALL Stat(	STATSTG		*pss,
+			DWORD		iStatFlags);
+};
+
+class	DocFileStorage;
+
+class	DocFileObject : public DocFileInternalFunctions
+{
+private:
+	df_int4		iEntryNumber;
+
+	friend class DocFileEnumStatStg;
+
+protected:
+	DocFileStorage	*pdfsParent;
+	df_char_t		*pchName;
+	DocFileManager	*pdfm;
+	DWORD		dwMode;
+
+	DocFileObject(	DocFileStorage	*pdfsParent_,
+			df_char_t const *pchName_,
+			DocFileManager	*pdfm_,
+			HRESULT		&hr,
+			df_byte		iType,
+			BOOL		bMustExist,
+			DWORD		dwMode);
+	DocFileObject(	DocFileObject	*pdfo,
+			HRESULT		&hr);
+	~DocFileObject(void);
+
+	HRESULT FindEntry(	BOOL	bMustExist,
+				df_byte iType);
+
+	inline	void
+	SetEntryNumber(df_int4 iEntry)
+	{
+		iEntryNumber = iEntry;
+	}
+
+	HRESULT Stat(	STATSTG		*pss,
+			DWORD		iStatFlags);
+
+public:
+	inline	df_int4
+	GetEntryNumber(void)
+	{
+		return iEntryNumber;
+	}
+};
+
+class	DocFileStorage : public IStorage,
+			public DocFileReferenceCounter,
+			public DocFileObject
+{
+protected:
+	~DocFileStorage(void);
+
+public:
+	DocFileStorage( DocFileStorage *pdfsParent_,
+			df_char_t const *pchName_,
+			DWORD		dwMode_,
+			DocFileManager	*pdfm_,
+			HRESULT		&hr_,
+			BOOL		bMustExist = FALSE);
+
+	HRESULT DF_STDCALL QueryInterface(REFIID	riid,
+			void		**ppvObj);
+	ULONG	DF_STDCALL AddRef(void) ;
+	ULONG	DF_STDCALL Release(void);
+
+	HRESULT DF_STDCALL CreateStream(df_char_t const *pchName,
+			DWORD		iMode,
+			DWORD		reserved1,
+			DWORD		reserved2,
+			IStream		**ppstm);
+	HRESULT DF_STDCALL OpenStream(df_char_t const	*pchName,
+			void		*reserved1,
+			DWORD		iMode,
+			DWORD		reserved2,
+			IStream		**ppstm);
+	HRESULT DF_STDCALL CreateStorage(df_char_t const *pchName,
+			DWORD		iMode,
+			DWORD		reserved1,
+			DWORD		reserved2,
+			IStorage	**ppstg);
+	HRESULT DF_STDCALL OpenStorage(df_char_t const	*pchName,
+			IStorage	*pstgPriority,
+			DWORD		iMode,
+			SNB		snbExclude,
+			DWORD		reserved,
+			IStorage	**ppstg);
+	HRESULT DF_STDCALL CopyTo(	DWORD		nExclude,
+			IID const	*piidExclude,
+			SNB		snbExclude,
+			IStorage	*pstgDest);
+	HRESULT DF_STDCALL MoveElementTo(df_char_t const *pchName,
+			IStorage	*pstgDest,
+			df_char_t const *pchNewName,
+			DWORD		iFlags);
+	HRESULT DF_STDCALL Commit(	DWORD		iCommitFlags);
+	HRESULT DF_STDCALL Revert(void);
+	HRESULT DF_STDCALL EnumElements(DWORD	reserved1,
+			void		*reserved2,
+			DWORD		reserved3,
+			IEnumSTATSTG	**ppiess);
+	HRESULT DF_STDCALL DestroyElement(df_char_t const *pchName);
+	HRESULT DF_STDCALL RenameElement(df_char_t const *pchOldName,
+			df_char_t const *pchNewName);
+	HRESULT DF_STDCALL SetElementTimes(df_char_t const *lpszName,
+			FILETIME const	*pftCreated,
+			FILETIME const	*pftAccessed,
+			FILETIME const	*pftModified);
+	HRESULT DF_STDCALL SetClass(REFCLSID	clsid);
+	HRESULT DF_STDCALL SetStateBits(DWORD	iStateBits,
+			DWORD		giMask);
+	HRESULT DF_STDCALL Stat(STATSTG		*pstatstg,
+			DWORD		iStatFlags);
+};
+
+struct	DocFile_StreamPtr
+{
+	df_int4 iDirectoryEntry;
+	df_int4 iPosition;
+	df_int4 iStreamBlock;
+	df_int4 iExtraBlocks;
+	BOOL	bFileStream;
+
+	DocFile_StreamPtr(void) :
+		iPosition(-1),
+		iDirectoryEntry(-1),
+		iStreamBlock(-1),
+		iExtraBlocks(0),
+		bFileStream(FALSE)
+	{
+	}
+};
+
+
+class	DocFileStream : public IStream,
+			public DocFileObject,
+			public DocFileReferenceCounter
+{
+private:
+	DocFile_StreamPtr	dfsp;
+
+	DocFileStream(	DocFileStream *pstr,
+			HRESULT		&hr);
+	void	FlushBuffer(void);
+	HRESULT PopulateBuffer(void);
+
+protected:
+	~DocFileStream(void);
+
+public:
+	DocFileStream(	DocFileStorage	*pdfsParent_,
+			df_char_t const *pchName_,
+			DocFileManager	*pdfm_,
+			DWORD		dwMode_,
+			BOOL		bMustExist,
+			HRESULT		&hr);
+
+	HRESULT DF_STDCALL QueryInterface(REFIID	riid,
+			void		**ppvObj);
+	ULONG	DF_STDCALL AddRef(void) ;
+	ULONG	DF_STDCALL Release(void);
+
+	HRESULT DF_STDCALL Read(	VOID		*pvData,
+			ULONG		nBytes,
+			ULONG		*pnRead);
+	HRESULT DF_STDCALL Write(	VOID const	*pvData,
+			ULONG		nBytes,
+			ULONG		*pnWritten);
+	HRESULT DF_STDCALL Seek(LARGE_INTEGER	iMove,
+			DWORD		dwOrigin,
+			ULARGE_INTEGER	*piNewPosition);
+	HRESULT DF_STDCALL SetSize(ULARGE_INTEGER	iNewSize);
+	HRESULT DF_STDCALL CopyTo(	IStream		*pstm,
+			ULARGE_INTEGER	nBytes,
+			ULARGE_INTEGER	*pnRead,
+			ULARGE_INTEGER	*pnWritten);
+	HRESULT DF_STDCALL Commit(	DWORD		iCommitFlags);
+	HRESULT DF_STDCALL Revert(void);
+	HRESULT DF_STDCALL LockRegion(ULARGE_INTEGER iOffset,
+			ULARGE_INTEGER	nBytes,
+			DWORD		dwLockType);
+	HRESULT DF_STDCALL UnlockRegion(ULARGE_INTEGER iOffset,
+			ULARGE_INTEGER	nBytes,
+			DWORD		dwLockType);
+	HRESULT DF_STDCALL Stat(	STATSTG		*pss,
+			DWORD		iStatFlags);
+	HRESULT DF_STDCALL Clone(	IStream		**ppstm);
+};
+
+#endif /* __DOCFILE_H */
diff -uN no-docfile/flokbyte.cpp docfile/flokbyte.cpp
--- no-docfile/flokbyte.cpp	1970-01-01 10:00:00.000000000 +1000
+++ docfile/flokbyte.cpp	2004-02-05 09:00:04.000000000 +1100
@@ -0,0 +1,290 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+static char const *rcsid = "$Id: flokbyte.cpp,v 1.4 1999/01/20 02:58:09 troy Exp $";
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#if defined(_Windows) || defined(WIN32) || defined(_WIN32) || defined(__WIN32)
+int	ftruncate(int, long);
+#else
+#include <unistd.h>
+#endif
+#include "docfile.h"
+
+FileLockBytes::FileLockBytes(	char const	*pchFileName_,
+				DWORD		dwMode_,
+				HRESULT		&hr) :
+	dwMode(dwMode_),
+	iSequence(0)
+{
+	int	iMode;
+
+	if (!pchFileName_)
+	{
+		pchFileName_ = tmpnam(0);
+		dwMode |= STGM_DELETEONRELEASE;
+	}
+	pchFileName = new char[strlen(pchFileName_) + 1];
+	strcpy(pchFileName, pchFileName_);
+
+	switch (dwMode & 0x3)
+	{
+	case STGM_READ:
+		iMode = O_RDONLY;
+		break;
+
+	case STGM_WRITE:
+		iMode = O_WRONLY;
+		break;
+
+	case STGM_READWRITE:
+		iMode = O_RDWR;
+		break;
+
+	default:
+		*(char *) 0 = 0;
+		break;
+	}
+	if (dwMode & STGM_CREATE)
+		iMode |= O_CREAT;
+
+	fd = open(pchFileName, iMode, 0666);
+	if (fd != -1)
+		hr = 0;
+	else
+		hr = TranslateError();
+}
+
+DEFINE_REFCOUNT(FileLockBytes);
+
+HRESULT
+FileLockBytes::GetCache(df_int4 iBlock,
+			int	&iCache)
+{
+	int	i;
+	int	iFound = -1;
+	df_int4 iBestSequence = iSequence;
+	df_int4 iBestFound = -1;
+	DF_Cache *pCache = aCache;
+	HRESULT hr;
+
+	for (i = 0; i < DF_FLB_BUFFERS; i++, pCache++)
+	{
+		if (pCache->iBlock == iBlock)
+		{
+			pCache->iLastUsed = iSequence++;
+			iCache = i;
+			return 0;
+		}
+		if (pCache->iBlock == -1 && iFound == -1)
+		{
+				iFound = i;
+		}
+		else if ((unsigned long) (iSequence - pCache->iLastUsed) >
+			    (unsigned long) (iSequence - iBestSequence))
+		{
+			iBestFound = i;
+			iBestSequence = pCache->iLastUsed;
+		}
+	}
+	if (iFound == -1)
+	{
+		Flush(iBestFound);
+		iFound = iBestFound;
+	}
+	pCache = aCache + iFound;
+	pCache->iLastUsed = iSequence++;
+	pCache->iBlock = iBlock;
+	pCache->bDirty = FALSE;
+	hr = MoveTo(iBlock * DF_BLOCK_SIZE);
+	if (hr)
+		memset(pCache->achData, 0, sizeof(pCache->achData));
+	else if (read(fd, pCache->achData, sizeof(pCache->achData)) < 0)
+		hr = TranslateError();
+	iCache = iFound;
+	return hr;
+}
+
+FileLockBytes::~FileLockBytes(void)
+{
+	Flush();
+	if (fd != -1)
+		close(fd);
+	if (dwMode & STGM_DELETEONRELEASE)
+		unlink(pchFileName);
+	delete [] pchFileName;
+}
+
+HRESULT DF_STDCALL
+FileLockBytes::ReadAt(	ULARGE_INTEGER	iOffset_,
+			VOID		*pvData,
+			ULONG		nBytes,
+			ULONG		*pnRead)
+{
+	int	iCacheEntry;
+	HRESULT hr;
+	df_int4 nRead = 0;
+	df_int4 iOffset;
+
+	Translate(&iOffset, &iOffset_);
+	while (nBytes)
+	{
+		df_int4 iBlock = iOffset / DF_BLOCK_SIZE;
+		int	iBOff = iOffset % DF_BLOCK_SIZE;
+		int	nNow = DF_BLOCK_SIZE - iBOff;
+		int	iCache;
+		HRESULT hr = GetCache(iBlock, iCache);
+
+		if (hr)
+		{
+			*pnRead = nRead;
+			return hr;
+		}
+
+		if (nNow > nBytes)
+			nNow = nBytes;
+		memcpy(pvData, aCache[iCache].achData + iBOff, nNow);
+		pvData = ((char *) pvData) + nNow;
+		iOffset += nNow;
+		nBytes -= nNow;
+		nRead += nNow;
+	}
+	*pnRead = nRead;
+	return 0;
+}
+
+HRESULT DF_STDCALL
+FileLockBytes::WriteAt(ULARGE_INTEGER	iOffset_,
+			VOID const	*pvData,
+			ULONG		nBytes,
+			ULONG		*pnWritten)
+{
+	int	iCacheEntry;
+	HRESULT hr;
+	df_int4 nWritten = 0;
+	df_int4 iOffset;
+
+	Translate(&iOffset, &iOffset_);
+	while (nBytes)
+	{
+		df_int4 iBlock = iOffset / DF_BLOCK_SIZE;
+		int	iBOff = iOffset % DF_BLOCK_SIZE;
+		int	nNow = DF_BLOCK_SIZE - iBOff;
+		int	iCache;
+		HRESULT hr = GetCache(iBlock, iCache);
+
+		if (hr)
+		{
+			*pnWritten= nWritten;
+			return hr;
+		}
+
+		if (nNow > nBytes)
+			nNow = nBytes;
+		memcpy(aCache[iCache].achData + iBOff, pvData, nNow);
+		pvData = ((char *) pvData) + nNow;
+		iOffset += nNow;
+		nBytes -= nNow;
+		nWritten += nNow;
+		aCache[iCache].bDirty = 1;
+	}
+	*pnWritten = nWritten;
+	return 0;
+}
+
+void
+FileLockBytes::Flush(int i)
+{
+	if (aCache[i].iBlock != -1 && aCache[i].bDirty)
+	{
+		lseek(fd, aCache[i].iBlock * DF_BLOCK_SIZE, 0);
+		write(fd, aCache[i].achData, sizeof(aCache[i].achData));
+	}
+}
+
+HRESULT DF_STDCALL
+FileLockBytes::Flush(void)
+{
+	int	i;
+
+	for (i = 0; i < DF_FLB_BUFFERS; i++)
+		Flush(i);
+	return 0;
+}
+
+HRESULT DF_STDCALL
+FileLockBytes::SetSize(ULARGE_INTEGER	nBytes_)
+{
+	HRESULT hr;
+	df_int4 nBytes;
+
+	hr = Translate(&nBytes, &nBytes_);
+	if (hr)
+		return hr;
+
+	if (ftruncate(fd, nBytes) == -1)
+		return TranslateError();
+	return 0;
+}
+
+HRESULT DF_STDCALL
+FileLockBytes::LockRegion(ULARGE_INTEGER iOffset,
+			ULARGE_INTEGER	nBytes,
+			DWORD		dwLockType)
+{
+	return 0;
+}
+
+HRESULT DF_STDCALL
+FileLockBytes::UnlockRegion(ULARGE_INTEGER iOffset,
+			ULARGE_INTEGER	nBytes,
+			DWORD		dwLockType)
+{
+	return 0;
+}
+
+HRESULT DF_STDCALL
+FileLockBytes::Stat(	STATSTG		*pss,
+			DWORD		iStatFlags)
+{
+	struct	stat	sbuf;
+
+	if (fstat(fd, &sbuf) == -1)
+		return TranslateError();
+
+	memset(pss, 0, sizeof(*pss));
+	pss->type = STGTY_LOCKBYTES;
+	Translate(&pss->cbSize, sbuf.st_size);
+	Translate(&pss->mtime, sbuf.st_mtime);
+	Translate(&pss->ctime, sbuf.st_ctime);
+	Translate(&pss->atime, sbuf.st_atime);
+	pss->grfMode = dwMode;
+}
+
+HRESULT
+FileLockBytes::MoveTo(	long	iOffset)
+{
+	if (lseek(fd, iOffset, 0) == -1)
+		return TranslateError();
+	return 0;
+}
diff -uN no-docfile/redblack.cpp docfile/redblack.cpp
--- no-docfile/redblack.cpp	1970-01-01 10:00:00.000000000 +1000
+++ docfile/redblack.cpp	2004-02-05 09:00:24.000000000 +1100
@@ -0,0 +1,423 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+static char const *rcsid = "$Id: redblack.cpp,v 1.3 1999/01/20 02:58:10 troy Exp $";
+#include "redblack.h"
+
+DF_RBNode::~DF_RBNode(void)
+{
+	if (apnChildren[0])
+		delete apnChildren[0];
+	if (apnChildren[1])
+		delete apnChildren[1];
+}
+
+DF_RBNode *
+DF_RBNode::GetParent(void)
+{
+	return pnParent;
+}
+
+DF_RBNode *
+DF_RBNode::GetUncle(void)
+{
+	DF_RBNode *pnGrandPappy;
+
+	if (!pnParent ||
+	    (pnGrandPappy = pnParent->pnParent) == 0 ||
+	    pnGrandPappy->pnParent == 0)
+		return 0;
+	return pnGrandPappy->apnChildren[1 - pnParent->GetSide()];
+}
+
+int
+DF_RBNode::GetSide(void)
+{
+	if (pnParent->apnChildren[0] == this)
+		return 0;
+	else
+		return 1;
+}
+
+DF_RBNode *
+DF_RBNode::GetChild(	int	iType)
+{
+	return apnChildren[iType];
+}
+
+void
+DF_RBNode::SetBlack(void)
+{
+	if (this)
+		dfde.iColour = DFRB_BLACK;
+}
+
+void
+DF_RBNode::SetRed(void)
+{
+	if (this)
+		dfde.iColour = DFRB_RED;
+}
+
+BOOL
+DF_RBNode::IsBlack(void)
+{
+	if (this) // OK, this *is* a hack
+		return dfde.iColour == DFRB_BLACK;
+	return TRUE;
+}
+
+BOOL
+DF_RBNode::IsRed(void)
+{
+	if (this) // OK, this *is* a hack
+		return dfde.iColour == DFRB_RED;
+	return FALSE;
+}
+
+void
+DF_RBNode::SetChild(	int	iType,
+			DF_RBNode *pnChild)
+{
+	df_int4 iChildID = pnChild ? pnChild->iDirEnt : -1;
+
+	apnChildren[iType] = pnChild;
+	if (!bRead)
+		return;
+	if (IsRoot())
+		SI4(dfde.iFirstChild) = iChildID;
+	else if (iType == DFRB_LEFT)
+		SI4(dfde.iLeftSibling) = iChildID;
+	else
+		SI4(dfde.iRightSibling) = iChildID;
+
+}
+
+void
+DF_RBNode::CheckInsertion(DocFileManager *pdfm)
+{
+	if (pnParent->IsRoot())
+	{
+		SetBlack();
+		return;
+	}
+
+	if (pnParent->IsBlack())
+	{
+		return;
+	}
+
+	DF_RBNode *pnUncle = GetUncle();
+	DF_RBNode *pnGrandPappy = pnParent->pnParent;
+
+	// OK, we're red, and our parent's red, what should we do?
+	if (pnUncle)
+		pnUncle->GetEntry(pdfm);
+
+	if (pnUncle->IsRed())
+	{
+		// If our uncle is red, split and cascade
+
+		pnParent->SetBlack();
+		pnParent->SetChanged();
+		pnUncle->SetBlack();
+		pnUncle->SetChanged();
+		pnGrandPappy->SetRed();
+		pnGrandPappy->SetChanged();
+		pnGrandPappy->CheckInsertion(pdfm);
+	}
+	else
+	{
+		// Our uncle is black, we need to rotate
+
+		int	iMySide = GetSide();
+		int	iDadsSide = pnParent->GetSide();
+
+		if (iMySide != iDadsSide)
+		{
+			// Double rotation. After this we're done.
+			pnParent->Rotate(iDadsSide);
+			pnParent->Rotate(iMySide);
+			SetBlack();
+			apnChildren[iMySide]->SetRed();
+		}
+		else
+		{
+			// Single rotation. After this we're done.
+			int	iOtherSide = 1 - iMySide;
+
+			pnGrandPappy->Rotate(iOtherSide);
+			pnParent->SetBlack();
+			pnParent->apnChildren[iOtherSide]->SetRed();
+		}
+	}
+}
+
+void
+DF_RBNode::CreateNew(DocFileManager *pdfm)
+{
+	bRead = TRUE;
+	pdfm->InitDirBlock(&dfde, 1);
+}
+
+void
+DF_RBNode::InsertInto(	DF_RBNode	*pnParent_,
+			int		iType,
+			DocFileManager	*pdfm)
+{
+	SetChanged();
+	pnParent = pnParent_;
+	pnParent->SetChild(iType, this);
+	pnParent->GetEntry(pdfm);
+	pnParent->SetChanged();
+	if (pnParent->IsRoot())
+	{
+		SetBlack();
+		return;
+	}
+	SetRed();
+	CheckInsertion(pdfm);
+}
+
+void
+DF_RBNode::Copy(DF_RBNode *pnSrc)
+{
+	int	iSide = GetSide();
+	BOOL	bBlack = IsBlack();
+
+	iDirEnt = pnSrc->iDirEnt;
+	dfde = pnSrc->dfde;
+	SetChild(0, apnChildren[0]);
+	SetChild(1, apnChildren[1]);
+	if (bBlack)
+		SetBlack();
+	else
+		SetRed();
+	SetChanged();
+	pnParent->SetChild(iSide, this);
+	pnParent->SetChanged();
+}
+
+void
+DF_RBNode::Rotate(	int	iDirection)
+{
+	int	iOtherSide = 1 - iDirection;
+	int	iSide = GetSide();
+	DF_RBNode	*pnChild = GetChild(iOtherSide);
+
+	pnParent->SetChanged();
+	pnChild->SetChanged();
+	SetChanged();
+
+	pnParent->SetChild(iSide, pnChild);
+	pnChild->pnParent = pnParent;
+	SetChild(iOtherSide, pnChild->apnChildren[iDirection]);
+	if (apnChildren[iOtherSide])
+		apnChildren[iOtherSide]->pnParent = this;
+	pnChild->SetChild(iDirection, this);
+	pnParent = pnChild;
+}
+
+void
+DF_RBNode::FixupDelete( DocFileManager *pdfm,
+			int		iSide)
+{
+	int	iSibling = 1 - iSide;
+	DF_RBNode *pnNearNephew, *pnFarNephew;
+
+	if (IsRoot() || apnChildren[iSide]->IsRed())
+	{
+		apnChildren[iSide]->SetBlack();
+		apnChildren[iSide]->SetChanged();
+		return;
+	}
+
+	apnChildren[iSibling]->Populate(pdfm);
+	apnChildren[iSibling]->PopulateChildren(pdfm);
+
+	if (apnChildren[iSibling]->IsRed())
+	{
+		apnChildren[iSibling]->SetBlack();
+		SetRed();
+		Rotate(iSide);
+		apnChildren[iSibling]->Populate(pdfm);
+		apnChildren[iSibling]->PopulateChildren(pdfm);
+	}
+
+	pnNearNephew = apnChildren[iSibling]->apnChildren[iSide];
+	pnFarNephew = apnChildren[iSibling]->apnChildren[iSibling];
+	if (pnNearNephew)
+		pnNearNephew->Populate(pdfm);
+	if (pnFarNephew)
+		pnFarNephew->Populate(pdfm);
+
+	if (pnNearNephew->IsBlack() && pnFarNephew->IsBlack())
+	{
+		apnChildren[iSibling]->SetRed();
+		apnChildren[iSibling]->SetChanged();
+		pnParent->FixupDelete(pdfm, GetSide());
+		return;
+	}
+	if (pnFarNephew->IsBlack())
+	{
+		pnNearNephew->SetBlack();
+		apnChildren[iSibling]->SetRed();
+		apnChildren[iSibling]->Rotate(iSibling);
+	}
+	if (IsRed())
+		apnChildren[iSibling]->SetRed();
+	else
+		apnChildren[iSibling]->SetBlack();
+	SetBlack();
+	pnFarNephew->SetBlack();
+	pnFarNephew->SetChanged();
+	Rotate(iSide);
+}
+
+DF_RBNode *
+DF_RBNode::Delete(DocFileManager *pdfm,
+		BOOL	bErase)
+{
+	DF_RBNode *pnUnlink, *pnRoot;
+	int	iMoveSide;
+	int	iSide = GetSide();
+	int	iDestSide = iSide;
+	int	iDirEnt_;
+	DocFile_DirEnt dfde_;
+
+	Populate(pdfm);
+	PopulateChildren(pdfm);
+
+	if (!apnChildren[DFRB_LEFT])
+	{
+		pnUnlink = this;
+		iMoveSide = DFRB_RIGHT;
+	}
+	else if (!apnChildren[DFRB_RIGHT])
+	{
+		pnUnlink = this;
+		iMoveSide = DFRB_LEFT;
+	}
+	else
+	{
+		pnUnlink = apnChildren[DFRB_RIGHT];
+		pnUnlink->Populate(pdfm);
+		pnUnlink->PopulateChildren(pdfm);
+		iMoveSide = DFRB_RIGHT;
+		iDestSide = DFRB_RIGHT;
+		while (pnUnlink->apnChildren[DFRB_LEFT])
+		{
+			pnUnlink = pnUnlink->apnChildren[DFRB_LEFT];
+			pnUnlink->Populate(pdfm);
+			pnUnlink->PopulateChildren(pdfm);
+			iDestSide = DFRB_LEFT;
+		}
+	}
+	if (pnUnlink->apnChildren[iMoveSide])
+		pnUnlink->apnChildren[iMoveSide]->pnParent = pnUnlink->pnParent;
+	pnUnlink->pnParent->SetChild(iDestSide, pnUnlink->apnChildren[iMoveSide]);
+	pnUnlink->pnParent->SetChanged();
+	SetChild(DFRB_LEFT, apnChildren[DFRB_LEFT]);
+	SetChild(DFRB_RIGHT, apnChildren[DFRB_RIGHT]);
+	SetChanged();
+
+	iDirEnt_ = iDirEnt;
+	dfde_ = dfde;
+
+	for (pnRoot = pnUnlink; pnRoot->pnParent; pnRoot = pnRoot->pnParent);
+
+	if (pnUnlink != this)
+	{
+		Copy(pnUnlink);
+	}
+	if (pnUnlink->IsBlack())
+		pnUnlink->pnParent->FixupDelete(pdfm, iDestSide);
+
+	if (bErase)
+		pdfm->InitDirBlock(&pnUnlink->dfde, 1);
+	else
+		pnUnlink->dfde = dfde_;
+	pnUnlink->SetChild(DFRB_LEFT, 0);
+	pnUnlink->SetChild(DFRB_RIGHT, 0);
+	pnUnlink->bRead = pnUnlink->bChanged = TRUE;
+	pnUnlink->iDirEnt = iDirEnt_;
+	pnUnlink->pnParent = pnRoot;
+	pnRoot->apnChildren[DFRB_RIGHT] = pnUnlink;
+	return pnUnlink;
+}
+
+
+HRESULT
+DF_RBNode::Populate(DocFileManager *pdfm)
+{
+	HRESULT hr;
+
+	if (!bRead)
+	{
+		hr = pdfm->GetDirectoryEntry(iDirEnt, &dfde);
+		if (!hr)
+			bRead = TRUE;
+	}
+	else
+	{
+		hr = 0;
+	}
+	return hr;
+}
+
+void
+DF_RBNode::PopulateChildren(DocFileManager *pdfm)
+{
+	if (!apnChildren[DFRB_LEFT])
+	{
+		df_int4 iDirEnt = SI4(dfde.iLeftSibling);
+
+		if (iDirEnt != -1)
+			apnChildren[DFRB_LEFT] = new DF_RBNode(iDirEnt, this);
+	}
+	if (!apnChildren[DFRB_RIGHT])
+	{
+		df_int4 iDirEnt = SI4(dfde.iRightSibling);
+
+		if (iDirEnt != -1)
+			apnChildren[DFRB_RIGHT] = new DF_RBNode(iDirEnt, this);
+	}
+}
+
+DocFile_DirEnt &
+DF_RBNode::GetEntry(DocFileManager *pdfm)
+{
+	if (!bRead)
+	{
+		Populate(pdfm);
+	}
+	return dfde;
+}
+
+
+void
+DF_RBNode::WriteChanges(DocFileManager *pdfm)
+{
+	if (bChanged)
+		pdfm->SetDirectoryEntry(iDirEnt, &dfde);
+	if (apnChildren[0])
+		apnChildren[0]->WriteChanges(pdfm);
+	if (apnChildren[1])
+		apnChildren[1]->WriteChanges(pdfm);
+}
diff -uN no-docfile/redblack.h docfile/redblack.h
--- no-docfile/redblack.h	1970-01-01 10:00:00.000000000 +1000
+++ docfile/redblack.h	2004-02-05 09:01:04.000000000 +1100
@@ -0,0 +1,118 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __REDBLACK_H
+#define __REDBLACK_H
+#ifndef __DFMGR_H
+#include "dfmgr.h"
+#endif
+
+/* Does the red-black trees for the directory lists */
+
+#define DFRB_LEFT	0
+#define DFRB_RIGHT	1
+
+#define DFRB_BLACK	1
+#define DFRB_RED	0
+
+class	DF_RBNode
+{
+private:
+	DF_RBNode	*pnParent;
+	DF_RBNode	*apnChildren[2];
+	df_int4		iDirEnt;
+
+	DocFile_DirEnt	dfde;
+
+	BOOL		bRead;
+	BOOL		bChanged;
+
+	void		Copy(DF_RBNode *pnSrc);
+
+	void		CheckInsertion(DocFileManager *pdfm);
+	void		FixupDelete(	DocFileManager *pdfm,
+					int		iSide);
+
+	int	GetSide(void);
+	DF_RBNode *GetParent(	void);
+	DF_RBNode *GetUncle(	void);
+
+	void	SetBlack(void);
+	void	SetRed(void);
+
+	BOOL	IsBlack(void);
+	BOOL	IsRed(void);
+
+	void	Rotate(int iDirection);
+
+public:
+	DF_RBNode(	df_int4 iDirEnt_,
+			DF_RBNode *pnParent_) :
+		pnParent(pnParent_),
+		iDirEnt(iDirEnt_),
+		bChanged(FALSE),
+		bRead(FALSE)
+	{
+		apnChildren[0] = apnChildren[1] = 0;
+	}
+
+	~DF_RBNode(void);
+
+	void	InsertInto(	DF_RBNode	*pnParent,
+				int		iType,
+				DocFileManager	*pdfm);
+	DF_RBNode *Delete(	DocFileManager *pdfm,
+				BOOL	bErase = TRUE);
+
+	HRESULT Populate(DocFileManager *pdfm);
+	void	PopulateChildren(DocFileManager *pdfm);
+	DocFile_DirEnt &GetEntry(DocFileManager *pdfm);
+	void	WriteChanges(DocFileManager *pdfm);
+	void	CreateNew(DocFileManager *pdfm);
+
+	void	SetChild(	int	iType,
+				DF_RBNode *pnChild);
+	DF_RBNode *GetChild(	int	iType);
+
+	inline	BOOL
+	IsPopulated(void)
+	{
+		return bRead;
+	}
+
+	inline	BOOL
+	IsRoot(void)
+	{
+		return !pnParent;
+	}
+
+	inline	void
+	SetChanged(void)
+	{
+		bChanged = TRUE;
+	}
+
+	inline	df_int4
+	GetDirEnt(void)
+	{
+		return iDirEnt;
+	}
+};
+
+#endif /* __REDBLACK_H */
diff -uN no-docfile/stgerr.h docfile/stgerr.h
--- no-docfile/stgerr.h	1970-01-01 10:00:00.000000000 +1000
+++ docfile/stgerr.h	2004-02-05 09:01:10.000000000 +1100
@@ -0,0 +1,37 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __STGERR_H
+#define __STGERR_H
+
+#ifndef S_OK
+#define S_OK			0L
+#endif
+#ifndef E_FAIL
+#define E_FAIL			0x80000008L
+#endif
+
+#define STG_E_FILENOTFOUND	0x80030001L
+#define STG_E_PATHNOTFOUND	0x80030003L
+#define STG_E_INSUFFICIENTMEMORY 0x80030008L
+#define STG_E_WRITEFAULT	0x8003001dL
+#define STG_E_READFAULT		0x8003001eL
+#define STG_E_FILEALREADYEXISTS 0x80030050L
+
+#endif /* __STGERR_H */
diff -uN no-docfile/storage.h docfile/storage.h
--- no-docfile/storage.h	1970-01-01 10:00:00.000000000 +1000
+++ docfile/storage.h	2004-02-05 09:01:15.000000000 +1100
@@ -0,0 +1,286 @@
+/* Compound Storage
+ *
+ * Copyright 1998-2003 CorVu Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __STORAGE_H
+#define __STORAGE_H
+#ifndef __DFTYPES_H
+#include "dftypes.h"
+#endif
+#ifndef __WINDOWS_H
+#ifndef __STGERR_H
+#include "stgerr.h"
+#endif
+
+#define STGM_DIRECT		0x00000000L
+#define STGM_TRANSACTED		0x00010000L
+
+#define STGM_READ		0x00000000L
+#define STGM_WRITE		0x00000001L
+#define STGM_READWRITE		0x00000002L
+
+#define STGM_SHARE_DENY_NONE	0x00000040L
+#define STGM_SHARE_DENY_READ	0x00000030L
+#define STGM_SHARE_DENY_WRITE	0x00000020L
+#define STGM_SHARE_EXCLUSIVE	0x00000010L
+
+#define STGM_PRIORITY		0x00040000L
+#define STGM_DELETEONRELEASE	0x04000000L
+
+#define STGM_CREATE		0x00001000L
+#define STGM_CONVERT		0x00020000L
+#define STGM_FAILIFTHERE	0x00000000L
+
+typedef enum tagSTGC
+{
+	STGC_DEFAULT				= 0,
+	STGC_OVERWRITE				= 1,
+	STGC_ONLYIFCURRENT			= 2,
+	STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4
+} STGC;
+
+typedef char **SNB;
+
+typedef struct tagSTATSTG
+{
+	char		*pwcsName;
+	DWORD		type;
+	ULARGE_INTEGER	cbSize;
+	FILETIME	mtime;
+	FILETIME	ctime;
+	FILETIME	atime;
+	DWORD		grfMode;
+	DWORD		grfLocksSupported;
+	CLSID		clsid;
+	DWORD		grfStateBits;
+	DWORD		reserved;
+} STATSTG;
+
+
+typedef enum tagSTGTY
+{
+	STGTY_STORAGE	= 1,
+	STGTY_STREAM	= 2,
+	STGTY_LOCKBYTES = 3,
+	STGTY_PROPERTY	= 4
+} STGTY;
+
+typedef enum tagSTREAM_SEEK
+{
+	STREAM_SEEK_SET = 0,
+	STREAM_SEEK_CUR = 1,
+	STREAM_SEEK_END = 2
+} STREAM_SEEK;
+
+typedef enum tagLOCKTYPE
+{
+	LOCK_WRITE	= 1,
+	LOCK_EXCLUSIVE	= 2,
+	LOCK_ONLYONCE	= 4
+} LOCKTYPE;
+
+typedef enum tagSTGMOVE
+{
+	STGMOVE_MOVE	= 0,
+	STGMOVE_COPY	= 1
+} STGMOVE;
+
+typedef enum tagSTATFLAG
+{
+	STATFLAG_DEFAULT = 0,
+	STATFLAG_NONAME = 1
+} STATFLAG;
+
+class	IUnknown
+{
+public:
+	virtual HRESULT QueryInterface(REFIID	riid,
+				void		**ppvObj) = 0;
+	virtual ULONG	AddRef(void)  = 0;
+	virtual ULONG	Release(void) = 0;
+};
+
+class IEnumSTATSTG : public IUnknown
+{
+public:
+	virtual HRESULT Next(	ULONG		nElements,
+				STATSTG		*pssElements,
+				ULONG		*pnFetched) = 0;
+	virtual HRESULT Skip(	ULONG		nElements) = 0;
+	virtual HRESULT Reset(void) = 0;
+	virtual HRESULT Clone(	IEnumSTATSTG	**ppiess) = 0;
+};
+
+typedef IEnumSTATSTG *LPENUMSTATSTG;
+
+
+
+class	ILockBytes : public IUnknown
+{
+public:
+	virtual HRESULT ReadAt( ULARGE_INTEGER	iOffset,
+				VOID		*pvData,
+				ULONG		nBytes,
+				ULONG		*pnRead) = 0;
+	virtual HRESULT WriteAt(ULARGE_INTEGER	iOffset,
+				VOID const	*pvData,
+				ULONG		nBytes,
+				ULONG		*pnWritten) = 0;
+	virtual HRESULT Flush(void) = 0;
+	virtual HRESULT SetSize(ULARGE_INTEGER	nBytes) = 0;
+	virtual HRESULT LockRegion(ULARGE_INTEGER iOffset,
+				ULARGE_INTEGER	nBytes,
+				DWORD		dwLockType) = 0;
+	virtual HRESULT UnlockRegion(ULARGE_INTEGER iOffset,
+				ULARGE_INTEGER	nBytes,
+				DWORD		dwLockType) = 0;
+	virtual HRESULT Stat(	STATSTG		*pss,
+				DWORD		iStatFlags) = 0;
+};
+
+typedef ILockBytes *LPLOCKBYTES;
+
+
+
+class	IStream : public IUnknown
+{
+public:
+	virtual HRESULT Read(	VOID		*pvData,
+				ULONG		nBytes,
+				ULONG		*pnRead) = 0;
+	virtual HRESULT Write(	VOID const	*pvData,
+				ULONG		nBytes,
+				ULONG		*pnWritten) = 0;
+	virtual HRESULT Seek(LARGE_INTEGER	iMove,
+				DWORD		dwOrigin,
+				ULARGE_INTEGER	*piNewPosition) = 0;
+	virtual HRESULT SetSize(ULARGE_INTEGER	iNewSize) = 0;
+	virtual HRESULT CopyTo( IStream		*pstm,
+				ULARGE_INTEGER	nBytes,
+				ULARGE_INTEGER	*pnRead,
+				ULARGE_INTEGER	*pnWritten) = 0;
+	virtual HRESULT Commit( DWORD		iCommitFlags) = 0;
+	virtual HRESULT Revert(void) = 0;
+	virtual HRESULT LockRegion(ULARGE_INTEGER iOffset,
+				ULARGE_INTEGER	nBytes,
+				DWORD		dwLockType) = 0;
+	virtual HRESULT UnlockRegion(ULARGE_INTEGER iOffset,
+				ULARGE_INTEGER	nBytes,
+				DWORD		dwLockType) = 0;
+	virtual HRESULT Stat(	STATSTG		*pss,
+				DWORD		iStatFlags) = 0;
+	virtual HRESULT Clone(	IStream		**ppstm) = 0;
+};
+
+typedef IStream *LPSTREAM;
+
+class	IStorage : public IUnknown
+{
+public:
+	virtual HRESULT CreateStream(char const *pchName,
+				DWORD		iMode,
+				DWORD		reserved1,
+				DWORD		reserved2,
+				IStream		**ppstm) = 0;
+	virtual HRESULT OpenStream(char const	*pchName,
+				void		*reserved1,
+				DWORD		iMode,
+				DWORD		reserved2,
+				IStream		**ppstm) = 0;
+	virtual HRESULT CreateStorage(char const *pchName,
+				DWORD		iMode,
+				DWORD		reserved1,
+				DWORD		reserved2,
+				IStorage	**ppstg) = 0;
+	virtual HRESULT OpenStorage(char const	*pchName,
+				IStorage	*pstgPriority,
+				DWORD		iMode,
+				SNB		snbExclude,
+				DWORD		reserved,
+				IStorage	**ppstg) = 0;
+	virtual HRESULT CopyTo( DWORD		nExclude,
+				IID const	*piidExclude,
+				SNB		snbExclude,
+				IStorage	*pstgDest) = 0;
+	virtual HRESULT MoveElementTo(char const *pchName,
+				IStorage	*pstgDest,
+				char const	*pchNewName,
+				DWORD		iFlags) = 0;
+	virtual HRESULT Commit( DWORD		iCommitFlags) = 0;
+	virtual HRESULT Revert(void) = 0;
+	virtual HRESULT EnumElements(DWORD	reserved1,
+				void		*reserved2,
+				DWORD		reserved3,
+				IEnumSTATSTG	**ppiess) = 0;
+	virtual HRESULT DestroyElement(char const *pchName) = 0;
+	virtual HRESULT RenameElement(char const *pchOldName,
+				char const	*pchNewName) = 0;
+	virtual HRESULT SetElementTimes(char const *lpszName,
+				FILETIME const	*pftCreated,
+				FILETIME const	*pftAccessed,
+				FILETIME const	*pftModified) = 0;
+	virtual HRESULT SetClass(REFCLSID	clsid) = 0;
+	virtual HRESULT SetStateBits(DWORD	iStateBits,
+				DWORD		giMask) = 0;
+	virtual HRESULT Stat(STATSTG		*pstatstg,
+				DWORD		iStatFlags) = 0;
+};
+
+typedef IStorage *LPSTORAGE;
+
+class	IRootStorage	: public	IUnknown
+{
+public:
+	virtual HRESULT SwitchToFile(LPSTR lpstrFile) = 0;
+};
+
+typedef IRootStorage *LPROOTSTORAGE;
+
+extern "C" {
+
+HRESULT StgCreateDocfile(char const	*pchName,
+			DWORD		iMode,
+			DWORD		reserved,
+			IStorage	**ppstgOpen);
+HRESULT StgCreateDocfileOnILockBytes(ILockBytes *plkbyt,
+			DWORD		iMode,
+			DWORD		reserved,
+			IStorage	**ppstgOpen);
+HRESULT StgOpenStorage( char const	*pchName,
+			IStorage	*pstgPriority,
+			DWORD		iMode,
+			SNB		snbExclude,
+			DWORD		reserved,
+			IStorage	**ppstgOpen);
+HRESULT StgOpenStorageOnILockBytes(ILockBytes *plkbyt,
+			IStorage	*pstgPriority,
+			DWORD		iMode,
+			SNB		snbExclude,
+			DWORD		reserved,
+			IStorage	**ppstgOpen);
+HRESULT StgIsStorageFile(char const	*pchName);
+HRESULT StgIsStorageILockBytes(ILockBytes *plkbyt);
+
+HRESULT StgSetTimes(	char const	*pchName,
+			FILETIME const	*pftCreated,
+			FILETIME const	*pftModified,
+			FILETIME const	*pftAccessed);
+} /* extern "C" */
+
+#endif /* __WINDOWS_H */
+#endif /* __STORAGE_H */


More information about the wine-devel mailing list