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.
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 */
On February 5, 2004 09:24 pm, Troy Rollo wrote:
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.
This is a lot of very nice code, too bad we can't use it in Wine as is. I sure hope someone will take the time to "port" it to Wine though.
On Tue, 10 Feb 2004 09:31:11 -0500, Dimitrie O. Paun wrote:
This is a lot of very nice code, too bad we can't use it in Wine as is. I sure hope someone will take the time to "port" it to Wine though.
Alexandre has said that C++ would be accepted given a good enough reason. Perhaps this is one? Though given how obscure some of that C++ is to somebody who doesn't know the language well, it might be best to just figure out what is missing from ours and fill it in.
On Tue, 10 Feb 2004, Mike Hearn wrote:
Alexandre has said that C++ would be accepted given a good enough reason. Perhaps this is one? Though given how obscure some of that C++ is to somebody who doesn't know the language well, it might be best to just figure out what is missing from ours and fill it in.
I'm afraid this is the way to go. Even if we were accepting C++, it's not good policy to simply replace entire pieces of code just like that. I guess there's no silver bullet: someone has to take the time, understand both pieces of code, and port the relavant pieces over. And it seems to me that "understand both pieces of code" is the hard part, once that is done, the C++ -> C port is trivial in comparison.