summaryrefslogtreecommitdiff
path: root/sot/source/sdstor
diff options
context:
space:
mode:
authorJens-Heiner Rechtien <hr@openoffice.org>2000-09-18 16:07:07 +0000
committerJens-Heiner Rechtien <hr@openoffice.org>2000-09-18 16:07:07 +0000
commit8ab086b6cc054501bfbf7ef6fa509c393691e860 (patch)
tree324d51845d7f1a2f4e02a14db22fb5947137c822 /sot/source/sdstor
parent411e68cc54ae97eebd79ae3a9cb2971b74cb2a9e (diff)
initial import
Diffstat (limited to 'sot/source/sdstor')
-rw-r--r--sot/source/sdstor/makefile.mk114
-rw-r--r--sot/source/sdstor/sdintern.hdb22
-rw-r--r--sot/source/sdstor/stg.cxx925
-rw-r--r--sot/source/sdstor/stgavl.cxx451
-rw-r--r--sot/source/sdstor/stgavl.hxx113
-rw-r--r--sot/source/sdstor/stgcache.cxx535
-rw-r--r--sot/source/sdstor/stgcache.hxx164
-rw-r--r--sot/source/sdstor/stgdir.cxx1032
-rw-r--r--sot/source/sdstor/stgdir.hxx170
-rw-r--r--sot/source/sdstor/stgelem.cxx433
-rw-r--r--sot/source/sdstor/stgelem.hxx204
-rw-r--r--sot/source/sdstor/stgio.cxx416
-rw-r--r--sot/source/sdstor/stgio.hxx121
-rw-r--r--sot/source/sdstor/stgole.cxx255
-rw-r--r--sot/source/sdstor/stgole.hxx111
-rw-r--r--sot/source/sdstor/stgstrms.cxx1268
-rw-r--r--sot/source/sdstor/stgstrms.hxx201
-rw-r--r--sot/source/sdstor/storage.cxx948
-rw-r--r--sot/source/sdstor/storinfo.cxx143
19 files changed, 7626 insertions, 0 deletions
diff --git a/sot/source/sdstor/makefile.mk b/sot/source/sdstor/makefile.mk
new file mode 100644
index 000000000000..47f2e4fa9815
--- /dev/null
+++ b/sot/source/sdstor/makefile.mk
@@ -0,0 +1,114 @@
+#*************************************************************************
+#
+# $RCSfile: makefile.mk,v $
+#
+# $Revision: 1.1.1.1 $
+#
+# last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $
+#
+# The Contents of this file are made available subject to the terms of
+# either of the following licenses
+#
+# - GNU Lesser General Public License Version 2.1
+# - Sun Industry Standards Source License Version 1.1
+#
+# Sun Microsystems Inc., October, 2000
+#
+# GNU Lesser General Public License Version 2.1
+# =============================================
+# Copyright 2000 by Sun Microsystems, Inc.
+# 901 San Antonio Road, Palo Alto, CA 94303, USA
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1, as published by the Free Software Foundation.
+#
+# 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
+#
+#
+# Sun Industry Standards Source License Version 1.1
+# =================================================
+# The contents of this file are subject to the Sun Industry Standards
+# Source License Version 1.1 (the "License"); You may not use this file
+# except in compliance with the License. You may obtain a copy of the
+# License at http://www.openoffice.org/license.html.
+#
+# Software provided under this License is provided on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+# See the License for the specific provisions governing your rights and
+# obligations concerning the Software.
+#
+# The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+#
+# Copyright: 2000 by Sun Microsystems, Inc.
+#
+# All Rights Reserved.
+#
+# Contributor(s): _______________________________________
+#
+#
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=sot
+TARGET=sdstor
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : svpre.mk
+.INCLUDE : settings.mk
+.INCLUDE : sv.mk
+
+# --- Files --------------------------------------------------------
+
+CXXFILES = \
+ stg.cxx \
+ stgcache.cxx \
+ stgstrms.cxx \
+ stgelem.cxx \
+ stgio.cxx \
+ stgole.cxx \
+ stgdir.cxx \
+ stgavl.cxx \
+ storinfo.cxx \
+ storage.cxx \
+ $(PROJECTPCHSOURCE).cxx
+
+SLOFILES = \
+ $(SLO)$/stg.obj \
+ $(SLO)$/stgcache.obj \
+ $(SLO)$/stgstrms.obj \
+ $(SLO)$/stgelem.obj \
+ $(SLO)$/stgio.obj \
+ $(SLO)$/stgole.obj \
+ $(SLO)$/stgdir.obj \
+ $(SLO)$/stgavl.obj \
+ $(SLO)$/storinfo.obj \
+ $(SLO)$/storage.obj
+
+# NETBSD: somewhere we have to instantiate the static data members.
+# NETBSD-1.2.1 doesn't know about weak symbols so the default mechanism for GCC won't work.
+# SCO and MACOSX: the linker does know about weak symbols, but we can't ignore multiple defined symbols
+.IF "$(OS)"=="NETBSD" || "$(OS)"=="SCO" || "$(OS)$(COM)"=="OS2GCC" || "$(OS)"=="MACOSX"
+SLOFILES+=$(SLO)$/staticmb.obj
+.ENDIF
+
+
+# --- Targets -------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/sot/source/sdstor/sdintern.hdb b/sot/source/sdstor/sdintern.hdb
new file mode 100644
index 000000000000..4dfbc69be013
--- /dev/null
+++ b/sot/source/sdstor/sdintern.hdb
@@ -0,0 +1,22 @@
+write "/*************************************************************************"
+write "* SDINTERN.HXX"
+write "* __DATE__"
+write "* (c) 1992-1995 STAR DIVISION"
+write "*************************************************************************/"
+write "#ifndef _SDINTERN_HXX"
+write "#define _SDINTERN_HXX"
+write "#ifndef _SOLAR_H"
+write "#include <tools/solar.h>"
+write "#endif"
+write "#ifndef _STREAM_HXX"
+write "#include <tools/stream.hxx>"
+write "#endif"
+file stg.hxx
+file stgelem.hxx
+file stgcache.hxx
+file stgio.hxx
+file stgstrms.hxx
+file stgavl.hxx
+file stgdir.hxx
+write "#endif"
+
diff --git a/sot/source/sdstor/stg.cxx b/sot/source/sdstor/stg.cxx
new file mode 100644
index 000000000000..4696b6a8c4d6
--- /dev/null
+++ b/sot/source/sdstor/stg.cxx
@@ -0,0 +1,925 @@
+/*************************************************************************
+ *
+ * $RCSfile: stg.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <storinfo.hxx>
+#ifndef _TOOLS_OWNLIST_HXX
+#include <tools/ownlist.hxx>
+#endif
+#ifndef _TOOLS_STRING_HXX
+#include <tools/string.hxx>
+#endif
+#ifndef _TOOLS_FSYS_HXX
+#include <tools/fsys.hxx>
+#endif
+#ifndef _TOOLS_STREAM_HXX
+#include <tools/stream.hxx>
+#endif
+#include <tools/pstm.hxx>
+#include <tools/debug.hxx>
+
+#include "stg.hxx"
+#include "stgelem.hxx"
+#include "stgcache.hxx"
+#include "stgstrms.hxx"
+#include "stgdir.hxx"
+#include "stgio.hxx"
+#include "stgole.hxx"
+#pragma hdrstop
+
+static long nTmpCount = 0;
+
+// The internal open mode is STREAM_READ | STREAM_TRUNC, which is silly
+// by itself. It inhibits the checking of sharing modes and is used
+// during CopyTo() and MoveTo() for opening a stream in read mode
+// although it may be open in DENYALL mode
+
+#define INTERNAL_MODE ( STREAM_READ | STREAM_TRUNC )
+
+///////////////////////// class StorageBase //////////////////////////////
+
+StorageBase::StorageBase( StgIo* p, StgDirEntry* pe )
+ : bAutoCommit( FALSE ), pIo( p ), pEntry( pe )
+{
+ nMode = STREAM_READ;
+ nError = SVSTREAM_OK;
+ p->IncRef();
+ if( pe )
+ pe->nRefCnt++;
+}
+
+StorageBase::~StorageBase()
+{
+ if( pEntry )
+ {
+ DBG_ASSERT( pEntry->nRefCnt, "RefCount unter 0" );
+ if( !--pEntry->nRefCnt )
+ {
+ if( pEntry->bZombie )
+ delete pEntry;
+ else
+ pEntry->Close();
+ }
+ }
+
+
+ if( !pIo->DecRef() )
+ delete pIo;
+}
+
+// Validate the instance for I/O
+
+BOOL StorageBase::Validate( BOOL bWrite ) const
+{
+ if( pEntry
+ && !pEntry->bInvalid
+ && ( !bWrite || !pEntry->bDirect || ( nMode & STREAM_WRITE ) ) )
+ return TRUE;
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return FALSE;
+}
+
+// Check the given share flags against the current flags
+
+BOOL StorageBase::ValidateMode( StreamMode m, StgDirEntry* p ) const
+{
+ if( m == INTERNAL_MODE )
+ return TRUE;
+ USHORT nCurMode = ( p && p->nRefCnt ) ? p->nMode : 0xFFFF;
+ if( ( m & 3 ) == STREAM_READ )
+ {
+ // only SHARE_DENYWRITE or SHARE_DENYALL allowed
+ if( ( ( m & STREAM_SHARE_DENYWRITE )
+ && ( nCurMode & STREAM_SHARE_DENYWRITE ) )
+ || ( ( m & STREAM_SHARE_DENYALL )
+ && ( nCurMode & STREAM_SHARE_DENYALL ) ) )
+ return TRUE;
+ }
+ else
+ {
+ // only SHARE_DENYALL allowed
+ // storages open in r/o mode are OK, since only
+ // the commit may fail
+ if( ( m & STREAM_SHARE_DENYALL )
+ && ( nCurMode & STREAM_SHARE_DENYALL ) )
+ return TRUE;
+ }
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return FALSE;
+}
+
+// The following three methods are declared as const, since they
+// may be called from within a const method.
+
+ULONG StorageBase::GetError() const
+{
+ ULONG n = nError;
+ ((StorageBase*) this)->nError = SVSTREAM_OK;
+ return n;
+}
+
+void StorageBase::SetError( ULONG n ) const
+{
+ if( !nError )
+ ((StorageBase*) this)->nError = n;
+}
+
+void StorageBase::ResetError() const
+{
+ ((StorageBase*) this)->nError = SVSTREAM_OK;
+}
+
+// Retrieve the underlying SvStream for info purposes
+
+const SvStream* StorageBase::GetSvStream() const
+{
+ return pIo ? pIo->GetStrm() : NULL;
+}
+
+//////////////////////// class StorageStream /////////////////////////////
+
+StorageStream::StorageStream( StgIo* p, StgDirEntry* q, StreamMode m )
+ : StorageBase( p, q ), nPos( 0L )
+{
+ // The dir entry may be 0; this means that the stream is invalid.
+ if( q )
+ {
+ if( q->nRefCnt == 1 )
+ {
+ q->nMode = m;
+ q->OpenStream( *p );
+ }
+ }
+ else
+ m &= ~STREAM_READWRITE;
+ nMode = m;
+}
+
+StorageStream::~StorageStream()
+{
+ // Do an auto-commit if the entry is open in direct mode
+ if( bAutoCommit )
+ Commit();
+ if( pEntry && pEntry->nRefCnt && pEntry->bDirect && (nMode & STREAM_WRITE) )
+ pEntry->Commit();
+}
+
+ULONG StorageStream::Read( void* pData, ULONG nSize )
+{
+ if( Validate() )
+ {
+ pEntry->Seek( nPos );
+ nSize = pEntry->Read( pData, (INT32) nSize );
+ pIo->MoveError( *this );
+ nPos += nSize;
+ }
+ else
+ nSize = 0L;
+ return nSize;
+}
+
+ULONG StorageStream::Write( const void* pData, ULONG nSize )
+{
+ if( Validate( TRUE ) )
+ {
+ pEntry->Seek( nPos );
+ nSize = pEntry->Write( pData, (INT32) nSize );
+ pIo->MoveError( *this );
+ nPos += nSize;
+ }
+ else
+ nSize = 0L;
+ return nSize;
+}
+
+ULONG StorageStream::Seek( ULONG n )
+{
+ if( Validate() )
+ return nPos = pEntry->Seek( n );
+ else
+ return n;
+}
+
+void StorageStream::Flush()
+{
+ // Flushing means committing, since streams are never transacted
+ Commit();
+}
+
+BOOL StorageStream::SetSize( ULONG nNewSize )
+{
+ if( Validate( TRUE ) )
+ {
+ BOOL b = pEntry->SetSize( (INT32) nNewSize );
+ pIo->MoveError( *this );
+ return b;
+ }
+ else
+ return FALSE;
+}
+
+BOOL StorageStream::Commit()
+{
+ if( !Validate() )
+ return FALSE;
+ if( !( nMode & STREAM_WRITE ) )
+ {
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return FALSE;
+ }
+ else
+ {
+ pEntry->Commit();
+ pIo->MoveError( *this );
+ return Good();
+ }
+}
+
+BOOL StorageStream::Revert()
+{
+ pEntry->Revert();
+ pIo->MoveError( *this );
+ return Good();
+}
+
+BOOL StorageStream::CopyTo( StorageStream* pDest )
+{
+ if( !Validate() || !pDest->Validate( TRUE ) || pEntry == pDest->pEntry )
+ return FALSE;
+ pEntry->Copy( *pDest->pEntry );
+ pDest->Commit();
+ pIo->MoveError( *this );
+ SetError( pDest->GetError() );
+ return BOOL( Good() && pDest->Good() );
+}
+
+///////////////////////// class SvStorageInfo //////////////////////////////
+
+SvStorageInfo::SvStorageInfo( const StgDirEntry& rE )
+{
+ rE.aEntry.GetName( aName );
+ bStorage = BOOL( rE.aEntry.GetType() == STG_STORAGE );
+ bStream = BOOL( rE.aEntry.GetType() == STG_STREAM );
+ nSize = bStorage ? 0 : rE.aEntry.GetSize();
+}
+
+/////////////////////////// class Storage ////////////////////////////////
+
+BOOL Storage::IsStorageFile( const String & rFileName )
+{
+ StgIo aIo;
+ if( aIo.Open( rFileName, STREAM_STD_READ ) )
+ return aIo.Load();
+ return FALSE;
+}
+
+// Open the storage file. If writing is permitted and the file is not
+// a storage file, initialize it.
+
+Storage::Storage( const String& rFile, StreamMode m, BOOL bDirect )
+ : StorageBase( new StgIo, NULL ), aName( rFile ), bIsRoot( FALSE )
+{
+ BOOL bTemp = FALSE;
+ if( !aName.Len() )
+ {
+ // no name = temporary name!
+ DirEntry aEntry;
+ aName = aEntry.TempName().GetFull();
+ bTemp = TRUE;
+ }
+ // the root storage creates the I/O system
+ nMode = m;
+ if( pIo->Open( aName, m ) )
+ {
+ Init( BOOL( ( m & ( STREAM_TRUNC | STREAM_NOCREATE ) ) == STREAM_TRUNC ) );
+ if( pEntry )
+ {
+ pEntry->bDirect = bDirect;
+ pEntry->nMode = m;
+ pEntry->bTemp = bTemp;
+ }
+ }
+ else
+ {
+ pIo->MoveError( *this );
+ pEntry = NULL;
+ }
+}
+
+// Create a storage on a given stream.
+
+Storage::Storage( SvStream& r, BOOL bDirect )
+ : StorageBase( new StgIo, NULL ), bIsRoot( FALSE )
+{
+ nMode = STREAM_READ;
+ if( r.IsWritable() )
+ nMode = STREAM_READ | STREAM_WRITE;
+ if( r.GetError() == SVSTREAM_OK )
+ {
+ pIo->SetStrm( &r, FALSE );
+ ULONG nSize = r.Seek( STREAM_SEEK_TO_END );
+ r.Seek( 0L );
+ // Initializing is OK if the stream is empty
+ Init( BOOL( nSize == 0 ) );
+ if( pEntry )
+ {
+ pEntry->bDirect = bDirect;
+ pEntry->nMode = nMode;
+ }
+ pIo->MoveError( *this );
+ }
+ else
+ {
+ SetError( r.GetError() );
+ pEntry = NULL;
+ }
+}
+
+// Perform common code for both ctors above.
+
+void Storage::Init( BOOL bCreate )
+{
+ pEntry = NULL;
+ BOOL bHdrLoaded = FALSE;
+ bIsRoot = TRUE;
+ if( pIo->Good() )
+ {
+ ULONG nSize = pIo->GetStrm()->Seek( STREAM_SEEK_TO_END );
+ pIo->GetStrm()->Seek( 0L );
+ if( nSize )
+ {
+ bHdrLoaded = pIo->Load();
+ if( !bHdrLoaded && !bCreate )
+ {
+ // File is not a storage and not empty; do not destroy!
+ SetError( SVSTREAM_FILEFORMAT_ERROR );
+ return;
+ }
+ }
+ }
+ // file is a storage, empty or should be overwritten
+ pIo->ResetError();
+ // we have to set up the data structures, since
+ // the file is empty
+ if( !bHdrLoaded )
+ pIo->Init();
+ if( pIo->Good() )
+ {
+ pEntry = pIo->pTOC->GetRoot();
+ pEntry->nRefCnt++;
+ }
+}
+
+// Internal ctor
+
+Storage::Storage( StgIo* p, StgDirEntry* q, StreamMode m )
+ : StorageBase( p, q ), bIsRoot( FALSE )
+{
+ if( q )
+ q->aEntry.GetName( aName );
+ else
+ m &= ~STREAM_READWRITE;
+ bIsRoot = FALSE;
+ nMode = m;
+ if( q && q->nRefCnt == 1 )
+ q->nMode = m;
+}
+
+Storage::~Storage()
+{
+ // Invalidate all open substorages
+ if( bAutoCommit )
+ Commit();
+ if( pEntry )
+ {
+ // Do an auto-commit if the entry is open in direct mode
+ if( pEntry->nRefCnt && pEntry->bDirect && (nMode & STREAM_WRITE) )
+ Commit();
+ if( pEntry->nRefCnt == 1 )
+ pEntry->Invalidate();
+ }
+ // close the stream is root storage
+ if( bIsRoot )
+ pIo->Close();
+ // remove the file if temporary root storage
+ if( bIsRoot && pEntry && pEntry->bTemp )
+ {
+ DirEntry aEntry( GetName() );
+ FSysError nErr = aEntry.Kill();
+ DBG_ASSERT( nErr == FSYS_ERR_OK, "cannot delete temp-file" )
+ }
+}
+
+const String& Storage::GetName() const
+{
+ if( !bIsRoot && Validate() )
+ pEntry->aEntry.GetName( ((Storage*) this)->aName );
+ return aName;
+}
+
+// Fill in the info list for this storage
+
+void Storage::FillInfoList( SvStorageInfoList* pList ) const
+{
+ if( Validate() )
+ {
+ StgIterator aIter( *pEntry );
+ StgDirEntry* p = aIter.First();
+ while( p )
+ {
+ if( !p->bInvalid )
+ {
+ SvStorageInfo aInfo( *p );
+ pList->Append( aInfo );
+ }
+ p = aIter.Next();
+ }
+ }
+}
+
+// Open or create a substorage
+
+Storage* Storage::OpenStorage( const String& rName, StreamMode m, BOOL bDirect )
+{
+ if( !Validate() || !ValidateMode( m, NULL ) )
+ return new Storage( pIo, NULL, m );
+ BOOL bSetAutoCommit = FALSE;
+ if( bDirect && !pEntry->bDirect )
+ {
+ bSetAutoCommit = TRUE;
+ bDirect = FALSE;
+ }
+
+ StgDirEntry* p = pIo->pTOC->Find( *pEntry, rName );
+ if( !p )
+ {
+ if( !( m & STREAM_NOCREATE ) )
+ {
+ BOOL bTemp = FALSE;
+ // create a new storage
+ String aNewName = rName;
+ if( !aNewName.Len() )
+ {
+ aNewName.AssignAscii( "Temp Stg " );
+ aNewName.Append( String::CreateFromInt32( ++nTmpCount ) );
+ bTemp = TRUE;
+ }
+ p = pIo->pTOC->Create( *pEntry, aNewName, STG_STORAGE );
+ if( p )
+ p->bTemp = bTemp;
+ }
+ if( !p )
+ pIo->SetError( ( m & STREAM_WRITE )
+ ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
+ }
+ else if( !ValidateMode( m, p ) )
+ p = NULL;
+ if( p && p->aEntry.GetType() != STG_STORAGE )
+ {
+ pIo->SetError( SVSTREAM_FILE_NOT_FOUND );
+ p = NULL;
+ }
+ // Dont check direct conflict if opening readonly
+ if( p && (m & STREAM_WRITE ))
+ {
+ // Either direct or transacted mode is supported
+ if( pEntry->nRefCnt == 1 )
+ p->bDirect = bDirect;
+ if( p->bDirect != bDirect )
+ SetError( SVSTREAM_ACCESS_DENIED );
+ }
+ Storage* pStg = new Storage( pIo, p, m );
+ pIo->MoveError( *pStg );
+ if( m & STREAM_WRITE ) pStg->bAutoCommit = TRUE;
+ return pStg;
+}
+
+// Open a stream
+
+StorageStream* Storage::OpenStream( const String& rName, StreamMode m, BOOL )
+{
+ if( !Validate() || !ValidateMode( m, NULL ) )
+ return new StorageStream( pIo, NULL, m );
+ StgDirEntry* p = pIo->pTOC->Find( *pEntry, rName );
+ BOOL bTemp = FALSE;
+ if( !p )
+ {
+ if( !( m & STREAM_NOCREATE ) )
+ {
+ // create a new stream
+ // make a name if the stream is temporary (has no name)
+ String aNewName( rName );
+ if( !aNewName.Len() )
+ {
+ aNewName.AssignAscii( "Temp Strm " );
+ aNewName.Append( String::CreateFromInt32( ++nTmpCount ) );
+ bTemp = TRUE;
+ }
+ p = pIo->pTOC->Create( *pEntry, aNewName, STG_STREAM );
+ }
+ if( !p )
+ pIo->SetError( ( m & STREAM_WRITE )
+ ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
+ }
+ else if( !ValidateMode( m, p ) )
+ p = NULL;
+ if( p && p->aEntry.GetType() != STG_STREAM )
+ {
+ pIo->SetError( SVSTREAM_FILE_NOT_FOUND );
+ p = NULL;
+ }
+ if( p )
+ {
+ p->bTemp = bTemp;
+ p->bDirect = pEntry->bDirect;
+ }
+ StorageStream* pStm = new StorageStream( pIo, p, m );
+ if( p && !p->bDirect )
+ pStm->bAutoCommit = TRUE;
+ pIo->MoveError( *pStm );
+ return pStm;
+}
+
+// Delete a stream or substorage by setting the temp bit.
+
+BOOL Storage::Remove( const String& rName )
+{
+ if( !Validate( TRUE ) )
+ return FALSE;
+ StgDirEntry* p = pIo->pTOC->Find( *pEntry, rName );
+ if( p )
+ {
+ p->Invalidate( TRUE );
+ return TRUE;
+ }
+ else
+ {
+ SetError( SVSTREAM_FILE_NOT_FOUND );
+ return FALSE;
+ }
+}
+
+// Rename a storage element
+
+BOOL Storage::Rename( const String& rOld, const String& rNew )
+{
+ if( Validate( TRUE ) )
+ {
+ BOOL b = pIo->pTOC->Rename( *pEntry, rOld, rNew );
+ pIo->MoveError( *this );
+ return b;
+ }
+ else
+ return FALSE;
+}
+
+// Copy one element
+
+BOOL Storage::CopyTo( const String& rElem, Storage* pDest, const String& rNew )
+{
+ if( !Validate() || !pDest || !pDest->Validate( TRUE ) )
+ return FALSE;
+ StgDirEntry* pElem = pIo->pTOC->Find( *pEntry, rElem );
+ if( pElem )
+ {
+ /*
+ this lines are misterious !!! MM
+ if( !pElem->IsContained( pDest->pEntry ) )
+ {
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return FALSE;
+ }
+ */
+ if( pElem->aEntry.GetType() == STG_STORAGE )
+ {
+ // copy the entire storage
+ Storage* p1 = OpenStorage( rElem, INTERNAL_MODE );
+ Storage* p2 = pDest->OpenStorage
+ ( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pEntry->bDirect );
+ p2->pEntry->aEntry.SetClassId( p1->pEntry->aEntry.GetClassId() );
+ p1->CopyTo( p2 );
+ SetError( p1->GetError() );
+ if( p2->GetError() )
+ pDest->SetError( p2->GetError() );
+ else
+ p2->Commit();
+ delete p1;
+ delete p2;
+ return BOOL( Good() && pDest->Good() );
+ }
+ else
+ {
+ // stream copy
+ StorageStream* p1 = OpenStream( rElem, INTERNAL_MODE );
+ StorageStream* p2 = pDest->OpenStream
+ ( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pEntry->bDirect );
+ p1->CopyTo( p2 );
+ SetError( p1->GetError() );
+ if( p2->GetError() )
+ pDest->SetError( p2->GetError() );
+ else
+ p2->Commit();
+ delete p1;
+ delete p2;
+ return BOOL( Good() && pDest->Good() );
+ }
+ }
+ SetError( SVSTREAM_FILE_NOT_FOUND );
+ return FALSE;
+}
+
+BOOL Storage::CopyTo( Storage* pDest ) const
+{
+ if( !Validate() || !pDest || !pDest->Validate( TRUE )
+ || pDest->pEntry == pEntry )
+ {
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return FALSE;
+ }
+ Storage* pThis = (Storage*) this;
+ /*
+ if( !pThis->pEntry->IsContained( pDest->pEntry ) )
+ {
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return FALSE;
+ }
+ */
+ pDest->pEntry->aEntry.SetClassId( pEntry->aEntry.GetClassId() );
+ pDest->pEntry->SetDirty();
+ SvStorageInfoList aList;
+ FillInfoList( &aList );
+ BOOL bRes = TRUE;
+ for( USHORT i = 0; i < aList.Count() && bRes; i++ )
+ {
+ SvStorageInfo& rInfo = aList.GetObject( i );
+ bRes = pThis->CopyTo( rInfo.GetName(), pDest, rInfo.GetName() );
+ }
+ if( !bRes )
+ SetError( pDest->GetError() );
+ return BOOL( Good() && pDest->Good() );
+}
+
+// Move one element
+
+BOOL Storage::MoveTo( const String& rElem, Storage* pDest, const String& rNew )
+{
+ if( !Validate() || !pDest || !pDest->Validate( TRUE )
+ || pDest->pEntry == pEntry )
+ {
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return FALSE;
+ }
+ StgDirEntry* pElem = pIo->pTOC->Find( *pEntry, rElem );
+ if( pElem )
+ {
+ // Simplest case: both storages share the same file
+ BOOL bRes;
+ if( pIo == pDest->pIo && rElem == rNew )
+ {
+ if( !pElem->IsContained( pDest->pEntry ) )
+ {
+ // cyclic move
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return FALSE;
+ }
+ bRes = pIo->pTOC->Move( *pEntry, *pDest->pEntry, rNew );
+ if( !bRes )
+ {
+ pIo->MoveError( *this );
+ pDest->pIo->MoveError( *pDest );
+ ULONG nErr = GetError();
+ if( !nErr )
+ nErr = pDest->GetError();
+ SetError( nErr );
+ pDest->SetError( nErr );
+ }
+ }
+ else
+ {
+ bRes = CopyTo( rElem, pDest, rNew );
+ if( bRes )
+ bRes = Remove( rElem );
+ }
+ if( !bRes )
+ SetError( pIo->GetError() );
+ return bRes;
+ }
+ SetError( SVSTREAM_FILE_NOT_FOUND );
+ return FALSE;
+}
+
+BOOL Storage::IsStorage( const String& rName ) const
+{
+ if( Validate() )
+ {
+ StgDirEntry* p = pIo->pTOC->Find( *pEntry, rName );
+ if( p )
+ return BOOL( p->aEntry.GetType() == STG_STORAGE );
+ }
+ return FALSE;
+}
+
+BOOL Storage::IsStream( const String& rName ) const
+{
+ if( Validate() )
+ {
+ StgDirEntry* p = pIo->pTOC->Find( *pEntry, rName );
+ if( p )
+ return BOOL( p->aEntry.GetType() == STG_STREAM );
+ }
+ return FALSE;
+}
+
+BOOL Storage::IsContained( const String& rName ) const
+{
+ if( Validate() )
+ return BOOL( pIo->pTOC->Find( *pEntry, rName ) != NULL );
+ else
+ return FALSE;
+}
+
+// Commit all sub-elements within this storage. If this is
+// the root, commit the FAT, the TOC and the header as well.
+
+BOOL Storage::Commit()
+{
+ BOOL bRes = TRUE;
+ if( !Validate() )
+ return FALSE;
+ if( !( nMode & STREAM_WRITE ) )
+ {
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return FALSE;
+ }
+ else
+ {
+ // Also commit the sub-streams and Storages
+ StgIterator aIter( *pEntry );
+ for( StgDirEntry* p = aIter.First(); p && bRes; p = aIter.Next() )
+ bRes = p->Commit();
+ if( bRes && bIsRoot )
+ {
+ bRes = pEntry->Commit();
+ if( bRes )
+ bRes = pIo->CommitAll();
+ }
+ pIo->MoveError( *this );
+ }
+ return bRes;
+}
+
+BOOL Storage::Revert()
+{
+ return TRUE;
+}
+
+///////////////////////////// OLE Support ////////////////////////////////
+
+// Set the storage type
+
+void Storage::SetClass( const SvGlobalName & rClass,
+ ULONG nOriginalClipFormat,
+ const String & rUserTypeName )
+{
+ if( Validate( TRUE ) )
+ {
+ // set the class name in the root entry
+ pEntry->aEntry.SetClassId( (const ClsId&) rClass.GetCLSID() );
+ pEntry->SetDirty();
+ // then create the streams
+ StgCompObjStream aCompObj( *this, TRUE );
+ aCompObj.GetClsId() = (const ClsId&) rClass.GetCLSID();
+ aCompObj.GetCbFormat() = nOriginalClipFormat;
+ aCompObj.GetUserName() = rUserTypeName;
+ if( !aCompObj.Store() )
+ SetError( aCompObj.GetError() );
+ else
+ {
+ StgOleStream aOle( *this, STREAM_WRITE );
+ if( !aOle.Store() )
+ SetError( aOle.GetError() );
+ }
+ }
+ else
+ SetError( SVSTREAM_ACCESS_DENIED );
+}
+
+void Storage::SetConvertClass( const SvGlobalName & rConvertClass,
+ ULONG nOriginalClipFormat,
+ const String & rUserTypeName )
+{
+ if( Validate( TRUE ) )
+ {
+ SetClass( rConvertClass, nOriginalClipFormat, rUserTypeName );
+ // plus the convert flag:
+ StgOleStream aOle( *this, TRUE );
+ aOle.GetFlags() |= 4;
+ if( !aOle.Store() )
+ SetError( aOle.GetError() );
+ }
+}
+
+SvGlobalName Storage::GetClassName()
+{
+ StgCompObjStream aCompObj( *this, FALSE );
+ if( aCompObj.Load() )
+ return SvGlobalName( (const CLSID&) aCompObj.GetClsId() );
+ pIo->ResetError();
+ return SvGlobalName();
+}
+
+ULONG Storage::GetFormat()
+{
+ StgCompObjStream aCompObj( *this, FALSE );
+ if( aCompObj.Load() )
+ return aCompObj.GetCbFormat();
+ pIo->ResetError();
+ return 0;
+}
+
+String Storage::GetUserName()
+{
+ StgCompObjStream aCompObj( *this, FALSE );
+ if( aCompObj.Load() )
+ return aCompObj.GetUserName();
+ pIo->ResetError();
+ return String();
+}
+
+BOOL Storage::ShouldConvert()
+{
+ StgOleStream aOle( *this, FALSE );
+ if( aOle.Load() )
+ return BOOL( ( aOle.GetFlags() & 4 ) != 0 );
+ else
+ {
+ pIo->ResetError();
+ return FALSE;
+ }
+}
+
+BOOL Storage::ValidateFAT()
+{
+ Link aLink = StgIo::GetErrorLink();
+ ErrCode nErr = pIo->ValidateFATs();
+ StgIo::SetErrorLink( aLink );
+ return nErr == ERRCODE_NONE;
+}
+
diff --git a/sot/source/sdstor/stgavl.cxx b/sot/source/sdstor/stgavl.cxx
new file mode 100644
index 000000000000..bd78852eb8e2
--- /dev/null
+++ b/sot/source/sdstor/stgavl.cxx
@@ -0,0 +1,451 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgavl.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+
+#include "stgavl.hxx"
+#pragma hdrstop
+
+StgAvlNode::StgAvlNode()
+{
+ pLeft = pRight = NULL;
+ nBalance = nId = 0;
+}
+
+StgAvlNode::~StgAvlNode()
+{
+ delete pLeft;
+ delete pRight;
+}
+
+StgAvlNode* StgAvlNode::Find( StgAvlNode* pFind )
+{
+ StgAvlNode* p = this;
+ while( p )
+ {
+ short nRes = p->Compare( pFind );
+ if( !nRes )
+ return p;
+ else p = ( nRes < 0 ) ? p->pLeft : p->pRight;
+ }
+ return NULL;
+}
+
+// find point to add node to AVL tree and returns
+// +/0/- for >/=/< previous
+
+short StgAvlNode::Locate
+ ( StgAvlNode* pFind,
+ StgAvlNode** pPivot, StgAvlNode **pParent, StgAvlNode** pPrev )
+{
+ short nRes;
+ StgAvlNode* pCur = this;
+ *pParent = *pPrev = NULL;
+ *pPivot = this;
+
+ // search tree for insertion point
+
+ while( pCur != NULL )
+ {
+ // check for pPivot
+ if( pCur->nBalance != 0 )
+ *pPivot = pCur, *pParent = *pPrev;
+ // save pPrev location and see what direction to go
+ *pPrev = pCur;
+ nRes = pCur->Compare( pFind );
+ if( nRes == 0 )
+ break;
+ else pCur = ( nRes < 0 ) ? pCur->pLeft : pCur->pRight;
+ }
+ return( nRes );
+}
+
+// adjust balance factors in AVL tree from pivot down.
+// Returns delta balance.
+
+short StgAvlNode::Adjust( StgAvlNode** pHeavy, StgAvlNode* pNew )
+{
+ StgAvlNode* pCur = this;
+ short nDelta;
+ // no traversing
+ if( pCur == pNew )
+ return nBalance;
+ short nRes = Compare( pNew );
+ if( nRes > 0 )
+ {
+ *pHeavy = pCur = pRight;
+ nDelta = -1;
+ }
+ else
+ {
+ *pHeavy = pCur = pLeft;
+ nDelta = 1;
+ }
+ nBalance = 0;
+ while( pCur != pNew )
+ {
+ nRes = pCur->Compare( pNew );
+ if( nRes > 0 )
+ {
+ // height of right increases by 1
+ pCur->nBalance = -1;
+ pCur = pCur->pRight;
+ }
+ else
+ {
+ // height of left increases by 1
+ pCur->nBalance = 1;
+ pCur = pCur->pLeft;
+ }
+ }
+ nBalance += nDelta;
+ return nDelta;
+}
+
+// perform LL rotation and return new root
+
+StgAvlNode* StgAvlNode::RotLL()
+{
+ StgAvlNode *pHeavy = pLeft;
+ pLeft = pHeavy->pRight;
+ pHeavy->pRight = this;
+ pHeavy->nBalance = nBalance = 0;
+ return pHeavy;
+}
+
+// perform LR rotation and return new root
+
+StgAvlNode* StgAvlNode::RotLR()
+{
+
+ StgAvlNode* pHeavy = pLeft;
+ StgAvlNode* pNewRoot = pHeavy->pRight;
+
+ pHeavy->pRight = pNewRoot->pLeft;
+ pLeft = pNewRoot->pRight;
+ pNewRoot->pLeft = pHeavy;
+ pNewRoot->pRight = this;
+
+ switch( pNewRoot->nBalance )
+ {
+ case 1: // LR( b )
+ nBalance = -1;
+ pHeavy->nBalance = 0;
+ break;
+ case -1: // LR( c )
+ pHeavy->nBalance = 1;
+ nBalance = 0;
+ break;
+ case 0: // LR( a )
+ nBalance = 0;
+ pHeavy->nBalance = 0;
+ break;
+ }
+ pNewRoot->nBalance = 0;
+ return pNewRoot;
+}
+
+// perform RR rotation and return new root
+
+StgAvlNode* StgAvlNode::RotRR()
+{
+ StgAvlNode* pHeavy = pRight;
+ pRight = pHeavy->pLeft;
+ pHeavy->pLeft = this;
+ nBalance = pHeavy->nBalance = 0;
+ return pHeavy;
+}
+
+// perform the RL rotation and return the new root
+
+StgAvlNode* StgAvlNode::RotRL()
+{
+ StgAvlNode* pHeavy = pRight;
+ StgAvlNode* pNewRoot = pHeavy->pLeft;
+ pHeavy->pLeft = pNewRoot->pRight;
+ pRight = pNewRoot->pLeft;
+ pNewRoot->pRight = pHeavy;
+ pNewRoot->pLeft = this;
+ switch( pNewRoot->nBalance )
+ {
+ case -1: // RL( b )
+ nBalance = 1;
+ pHeavy->nBalance = 0;
+ break;
+ case 1: // RL( c )
+ pHeavy->nBalance = -1;
+ nBalance = 0;
+ break;
+ case 0: // RL( a )
+ nBalance = 0;
+ pHeavy->nBalance = 0;
+ break;
+ }
+ pNewRoot->nBalance = 0;
+ return pNewRoot;
+}
+
+// Remove a tree element. Return the removed element or NULL.
+
+StgAvlNode* StgAvlNode::Rem( StgAvlNode** p, StgAvlNode* pDel, BOOL bPtrs )
+{
+ if( *p )
+ {
+ StgAvlNode* pCur = *p;
+ short nRes = bPtrs ? ( pCur == pDel ) : pCur->Compare( pDel );
+ if( !nRes )
+ {
+ // Element found: remove
+ if( !pCur->pRight )
+ {
+ *p = pCur->pLeft; pCur->pLeft = NULL;
+ }
+ else if( !pCur->pLeft )
+ {
+ *p = pCur->pRight; pCur->pRight = NULL;
+ }
+ else
+ {
+ // The damn element has two leaves. Get the
+ // rightmost element of the left subtree (which
+ // is lexically before this element) and replace
+ // this element with the element found.
+ StgAvlNode* last = pCur;
+ StgAvlNode* l;
+ for( l = pCur->pLeft;
+ l->pRight; last = l, l = l->pRight ) {}
+ // remove the element from chain
+ if( l == last->pRight )
+ last->pRight = l->pLeft;
+ else
+ last->pLeft = l->pLeft;
+ // perform the replacement
+ l->pLeft = pCur->pLeft;
+ l->pRight = pCur->pRight;
+ *p = l;
+ // delete the element
+ pCur->pLeft = pCur->pRight = NULL;
+ }
+ return pCur;
+ }
+ else
+ {
+ if( nRes < 0 )
+ return Rem( &pCur->pLeft, pDel, bPtrs );
+ else
+ return Rem( &pCur->pRight, pDel, bPtrs );
+ }
+ }
+ return NULL;
+}
+
+// Enumerate the tree for later iteration
+
+void StgAvlNode::Enum( short& n )
+{
+ if( this )
+ {
+ if( pLeft )
+ pLeft->Enum( n );
+ nId = n++;
+ if( pRight )
+ pRight->Enum( n );
+ }
+}
+
+// Add node to AVL tree.
+// Return FALSE if the element already exists.
+
+BOOL StgAvlNode::Insert( StgAvlNode** pRoot, StgAvlNode* pIns )
+{
+ StgAvlNode* pPivot, *pHeavy, *pNewRoot, *pParent, *pPrev;
+ // special case - empty tree
+ if( *pRoot == NULL )
+ {
+ *pRoot = pIns;
+ return TRUE;
+ }
+ // find insertion point and return if already present
+ short nRes = (*pRoot)->Locate( pIns, &pPivot, &pParent, &pPrev );
+ if( !nRes )
+ return FALSE;
+ // add new node
+ if( nRes < 0 )
+ pPrev->pLeft = pIns;
+ else
+ pPrev->pRight = pIns;
+ // rebalance tree
+ short nDelta = pPivot->Adjust( &pHeavy, pIns );
+ if( pPivot->nBalance >= 2 || pPivot->nBalance <= -2 )
+ {
+ pHeavy = ( nDelta < 0 ) ? pPivot->pRight : pPivot->pLeft;
+ // left imbalance
+ if( nDelta > 0 )
+ if( pHeavy->nBalance == 1 )
+ pNewRoot = pPivot->RotLL();
+ else
+ pNewRoot = pPivot->RotLR();
+ // right imbalance
+ else if( pHeavy->nBalance == -1 )
+ pNewRoot = pPivot->RotRR();
+ else
+ pNewRoot = pPivot->RotRL();
+ // relink balanced subtree
+ if( pParent == NULL )
+ *pRoot = pNewRoot;
+ else if( pPivot == pParent->pLeft )
+ pParent->pLeft = pNewRoot;
+ else if( pPivot == pParent->pRight )
+ pParent->pRight = pNewRoot;
+ }
+ return TRUE;
+}
+
+// Remove node from tree. Returns TRUE is found and removed.
+// Actually delete if bDel
+
+BOOL StgAvlNode::Remove( StgAvlNode** pRoot, StgAvlNode* pDel, BOOL bDel )
+{
+ // special case - empty tree
+ if( *pRoot == NULL )
+ return FALSE;
+ // delete the element
+ pDel = Rem( pRoot, pDel, FALSE );
+ if( pDel )
+ {
+ if( bDel )
+ delete pDel;
+ // Rebalance the tree the hard way
+ // OS 22.09.95: Auf MD's Wunsch auskommentiert wg. Absturz
+/* StgAvlNode* pNew = NULL;
+ while( *pRoot )
+ {
+ StgAvlNode* p = Rem( pRoot, *pRoot, FALSE );
+ Insert( &pNew, p );
+ }
+ *pRoot = pNew;*/
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+// Move node to a different tree. Returns TRUE is found and moved. This routine
+// may be called when the key has changed.
+
+BOOL StgAvlNode::Move
+ ( StgAvlNode** pRoot1, StgAvlNode** pRoot2, StgAvlNode* pMove )
+{
+ // special case - empty tree
+ if( *pRoot1 == NULL )
+ return FALSE;
+ pMove = Rem( pRoot1, pMove, FALSE );
+ if( pMove )
+ return Insert( pRoot2, pMove );
+ else
+ return FALSE;
+}
+
+////////////////////////// class AvlIterator /////////////////////////
+
+// The iterator walks through a tree one entry by one.
+
+StgAvlIterator::StgAvlIterator( StgAvlNode* p )
+{
+ pRoot = p;
+ nCount = 0;
+ if( p )
+ p->Enum( nCount );
+}
+
+StgAvlNode* StgAvlIterator::Find( short n )
+{
+ StgAvlNode* p = pRoot;
+ while( p )
+ {
+ if( n == p->nId )
+ break;
+ else p = ( n < p->nId ) ? p->pLeft : p->pRight;
+ }
+ return p;
+}
+
+StgAvlNode* StgAvlIterator::First()
+{
+ nCur = -1;
+ return Next();
+}
+
+StgAvlNode* StgAvlIterator::Last()
+{
+ nCur = nCount;
+ return Prev();
+}
+
+StgAvlNode* StgAvlIterator::Next()
+{
+ return Find( ++nCur );
+}
+
+StgAvlNode* StgAvlIterator::Prev()
+{
+ return Find( --nCur );
+}
+
diff --git a/sot/source/sdstor/stgavl.hxx b/sot/source/sdstor/stgavl.hxx
new file mode 100644
index 000000000000..e9ab60dcea4f
--- /dev/null
+++ b/sot/source/sdstor/stgavl.hxx
@@ -0,0 +1,113 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgavl.hxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifndef _STGAVL_HXX
+#define _STGAVL_HXX
+
+#ifndef _TOOLS_SOLAR_H
+#include <tools/solar.h>
+#endif
+
+// This class must be overloaded to define real, living nodes.
+// Especially, the compare function must be implemented.
+
+class StgAvlNode
+{
+ friend class StgAvlIterator;
+private:
+ short Locate( StgAvlNode*, StgAvlNode**, StgAvlNode**, StgAvlNode** );
+ short Adjust( StgAvlNode**, StgAvlNode* );
+ StgAvlNode* RotLL();
+ StgAvlNode* RotLR();
+ StgAvlNode* RotRR();
+ StgAvlNode* RotRL();
+ void Enum( short& );
+ static StgAvlNode* Rem( StgAvlNode**, StgAvlNode*, BOOL );
+protected:
+ short nId; // iterator ID
+ short nBalance; // indicates tree balance
+ StgAvlNode* pLeft, *pRight; // leaves
+ StgAvlNode();
+public:
+ virtual ~StgAvlNode();
+ StgAvlNode* Find( StgAvlNode* );
+ static BOOL Insert( StgAvlNode**, StgAvlNode* );
+ static BOOL Remove( StgAvlNode**, StgAvlNode*, BOOL bDel = TRUE );
+ static BOOL Move( StgAvlNode**, StgAvlNode**, StgAvlNode* );
+ virtual short Compare( const StgAvlNode* ) const = 0;
+};
+
+// The iterator class provides single stepping through an AVL tree.
+
+class StgAvlIterator {
+ StgAvlNode* pRoot; // root entry (parent)
+ short nCount; // tree size
+ short nCur; // current element
+ StgAvlNode* Find( short );
+public:
+ StgAvlIterator( StgAvlNode* );
+ StgAvlNode* First();
+ StgAvlNode* Last();
+ StgAvlNode* Next();
+ StgAvlNode* Prev();
+};
+
+#endif
diff --git a/sot/source/sdstor/stgcache.cxx b/sot/source/sdstor/stgcache.cxx
new file mode 100644
index 000000000000..c5381f69a540
--- /dev/null
+++ b/sot/source/sdstor/stgcache.cxx
@@ -0,0 +1,535 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgcache.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#if defined(_MSC_VER) && (_MSC_VER<1200)
+#include <tools/presys.h>
+#endif
+#if STLPORT_VERSION<321
+#include <hash_map.h>
+#else
+#include <hash_map>
+#endif
+#if defined(_MSC_VER) && (_MSC_VER<1200)
+#include <tools/postsys.h>
+#endif
+#include <vos/macros.hxx>
+
+#include <string.h>
+
+#ifndef _TOOLS_STRING_HXX
+#include <tools/string.hxx>
+#endif
+
+#include "stg.hxx"
+#include "stgelem.hxx"
+#include "stgcache.hxx"
+#include "stgstrms.hxx"
+#include "stgdir.hxx"
+#include "stgio.hxx"
+#pragma hdrstop
+
+/*************************************************************************/
+//-----------------------------------------------------------------------------
+typedef NAMESPACE_STD(hash_map)
+//typedef hash_map
+<
+ INT32,
+ StgPage *,
+ NAMESPACE_STD(hash)< INT32 >,
+ NAMESPACE_STD(equal_to)< INT32 >
+> UsrStgPagePtr_Impl;
+#ifdef WNT
+#pragma warning( disable: 4786 )
+#endif
+
+//#define CHECK_DIRTY 1
+//#define READ_AFTER_WRITE 1
+
+////////////////////////////// class StgPage /////////////////////////////
+// This class implements buffer functionality. The cache will always return
+// a page buffer, even if a read fails. It is up to the caller to determine
+// the correctness of the I/O.
+
+StgPage::StgPage( StgCache* p, short n )
+{
+ pCache = p;
+ nData = n;
+ bDirty = FALSE;
+ nPage = 0;
+ pData = new BYTE[ nData ];
+ pNext1 =
+ pNext2 =
+ pLast1 =
+ pLast2 = NULL;
+ pOwner = NULL;
+}
+
+StgPage::~StgPage()
+{
+ delete pData;
+}
+
+void StgPage::SetPage( short nOff, INT32 nVal )
+{
+ if( ( nOff < (short) ( nData / sizeof( INT32 ) ) ) && nOff >= 0 )
+ {
+#ifdef __BIGENDIAN
+ nVal = SWAPLONG(nVal);
+#endif
+ ((INT32*) pData )[ nOff ] = nVal;
+ bDirty = TRUE;
+ }
+}
+
+//////////////////////////////// class StgCache ////////////////////////////
+
+// The disk cache holds the cached sectors. The sector type differ according
+// to their purpose.
+
+StgCache::StgCache()
+{
+ nRef = 0;
+ pStrm = NULL;
+ pCur = pElem1 = NULL;
+ nPageSize = 512;
+ nError = SVSTREAM_OK;
+ bMyStream = FALSE;
+ bFile = FALSE;
+ pLRUCache = NULL;
+}
+
+StgCache::~StgCache()
+{
+ Clear();
+ SetStrm( NULL, FALSE );
+ delete (UsrStgPagePtr_Impl*)pLRUCache;
+}
+
+void StgCache::SetPhysPageSize( short n )
+{
+ nPageSize = n;
+ ULONG nPos = pStrm->Tell();
+ ULONG nFileSize = pStrm->Seek( STREAM_SEEK_TO_END );
+ nPages = ( nFileSize >= 512 ) ? ( nFileSize - 512 ) / nPageSize : 0;
+ pStrm->Seek( nPos );
+}
+
+// Create a new cache element
+// pCur points to this element
+
+StgPage* StgCache::Create( INT32 nPg )
+{
+ StgPage* pElem = new StgPage( this, nPageSize );
+ pElem->nPage = nPg;
+ // For data security, clear the buffer contents
+ memset( pElem->pData, 0, pElem->nData );
+
+ // insert to LRU
+ if( pCur )
+ {
+ pElem->pNext1 = pCur;
+ pElem->pLast1 = pCur->pLast1;
+ pElem->pNext1->pLast1 =
+ pElem->pLast1->pNext1 = pElem;
+ }
+ else
+ pElem->pNext1 = pElem->pLast1 = pElem;
+ if( !pLRUCache )
+ pLRUCache = new UsrStgPagePtr_Impl();
+ (*(UsrStgPagePtr_Impl*)pLRUCache)[pElem->nPage] = pElem;
+ pCur = pElem;
+
+ // insert to Sorted
+ if( !pElem1 )
+ pElem1 = pElem->pNext2 = pElem->pLast2 = pElem;
+ else
+ {
+ StgPage* p = pElem1;
+ do
+ {
+ if( pElem->nPage < p->nPage )
+ break;
+ p = p->pNext2;
+ } while( p != pElem1 );
+ pElem->pNext2 = p;
+ pElem->pLast2 = p->pLast2;
+ pElem->pNext2->pLast2 =
+ pElem->pLast2->pNext2 = pElem;
+ if( p->nPage < pElem1->nPage )
+ pElem1 = pElem;
+ }
+ return pElem;
+}
+
+// Delete the given element
+
+void StgCache::Erase( StgPage* pElem )
+{
+ //remove from LRU
+ pElem->pNext1->pLast1 = pElem->pLast1;
+ pElem->pLast1->pNext1 = pElem->pNext1;
+ if( pCur == pElem )
+ pCur = ( pElem->pNext1 == pElem ) ? NULL : pElem->pNext1;
+ if( pLRUCache )
+ ((UsrStgPagePtr_Impl*)pLRUCache)->erase( pElem->nPage );
+ // remove from Sorted
+ pElem->pNext2->pLast2 = pElem->pLast2;
+ pElem->pLast2->pNext2 = pElem->pNext2;
+ if( pElem1 == pElem )
+ pElem1 = ( pElem->pNext2 == pElem ) ? NULL : pElem->pNext2;
+ delete pElem;
+}
+
+// remove all cache elements without flushing them
+
+void StgCache::Clear()
+{
+ StgPage* pElem = pCur;
+ if( pCur ) do
+ {
+ StgPage* pDelete = pElem;
+ pElem = pElem->pNext1;
+ delete pDelete;
+ }
+ while( pCur != pElem );
+ pCur = NULL;
+ pElem1 = NULL;
+ delete (UsrStgPagePtr_Impl*)pLRUCache;
+ pLRUCache = NULL;
+}
+
+// Look for a cached page
+
+StgPage* StgCache::Find( INT32 nPage )
+{
+ if( !pLRUCache )
+ return NULL;
+ UsrStgPagePtr_Impl::iterator aIt = ((UsrStgPagePtr_Impl*)pLRUCache)->find( nPage );
+ if( aIt != ((UsrStgPagePtr_Impl*)pLRUCache)->end() )
+ {
+ // page found
+ StgPage* pFound = (*aIt).second;
+
+ if( pFound != pCur )
+ {
+ // remove from LRU
+ pFound->pNext1->pLast1 = pFound->pLast1;
+ pFound->pLast1->pNext1 = pFound->pNext1;
+ // insert to LRU
+ pFound->pNext1 = pCur;
+ pFound->pLast1 = pCur->pLast1;
+ pFound->pNext1->pLast1 =
+ pFound->pLast1->pNext1 = pFound;
+ }
+ return pFound;
+ }
+ return NULL;
+}
+
+// Load a page into the cache
+
+StgPage* StgCache::Get( INT32 nPage, BOOL bForce )
+{
+ StgPage* p = Find( nPage );
+ if( !p )
+ {
+ p = Create( nPage );
+ if( !Read( nPage, p->pData, 1 ) && bForce )
+ {
+ Erase( p );
+ p = NULL;
+ SetError( SVSTREAM_READ_ERROR );
+ }
+ }
+ return p;
+}
+
+// Copy an existing page into a new page. Use this routine
+// to duplicate an existing stream or to create new entries.
+// The new page is initially marked dirty. No owner is copied.
+
+StgPage* StgCache::Copy( INT32 nNew, INT32 nOld )
+{
+ StgPage* p = Find( nNew );
+ if( !p )
+ p = Create( nNew );
+ if( nOld >= 0 )
+ {
+ // old page: we must have this data!
+ StgPage* q = Get( nOld, TRUE );
+ if( q )
+ memcpy( p->pData, q->pData, p->nData );
+ }
+ p->SetDirty();
+ return p;
+}
+
+// Flush the cache whose owner is given. NULL flushes all.
+
+BOOL StgCache::Commit( StgDirEntry* )
+{
+ StgPage* p = pElem1;
+ if( p ) do
+ {
+ if( p->bDirty )
+ {
+ BOOL b = Write( p->nPage, p->pData, 1 );
+ if( !b )
+ return FALSE;
+ p->bDirty = FALSE;
+ }
+ p = p->pNext2;
+ } while( p != pElem1 );
+ pStrm->Flush();
+ SetError( pStrm->GetError() );
+#ifdef CHECK_DIRTY
+ p = pElem1;
+ if( p ) do
+ {
+ if( p->bDirty )
+ {
+ ErrorBox( NULL, WB_OK, String("SO2: Dirty Block in Ordered List") ).Execute();
+ BOOL b = Write( p->nPage, p->pData, 1 );
+ if( !b )
+ return FALSE;
+ p->bDirty = FALSE;
+ }
+ p = p->pNext2;
+ } while( p != pElem1 );
+ p = pElem1;
+ if( p ) do
+ {
+ if( p->bDirty )
+ {
+ ErrorBox( NULL, WB_OK, String("SO2: Dirty Block in LRU List") ).Execute();
+ BOOL b = Write( p->nPage, p->pData, 1 );
+ if( !b )
+ return FALSE;
+ p->bDirty = FALSE;
+ }
+ p = p->pNext1;
+ } while( p != pElem1 );
+#endif
+ return TRUE;
+}
+
+void StgCache::Revert( StgDirEntry* )
+{}
+
+// Set a stream
+
+void StgCache::SetStrm( SvStream* p, BOOL bMy )
+{
+ if( bMyStream )
+ delete pStrm;
+ pStrm = p;
+ bMyStream = bMy;
+}
+
+// Open/close the disk file
+
+BOOL StgCache::Open( const String& rName, StreamMode nMode )
+{
+ // do not open in exclusive mode!
+ if( nMode & STREAM_SHARE_DENYALL )
+ nMode = ( ( nMode & ~STREAM_SHARE_DENYALL ) | STREAM_SHARE_DENYWRITE );
+ SvFileStream* pFileStrm = new SvFileStream( rName, nMode );
+ // SvStream "Feature" Write Open auch erfolgreich, wenns nicht klappt
+ BOOL bAccessDenied = FALSE;
+ if( ( nMode & STREAM_WRITE ) && !pFileStrm->IsWritable() )
+ {
+ pFileStrm->Close();
+ bAccessDenied = TRUE;
+ }
+ SetStrm( pFileStrm, TRUE );
+ if( pFileStrm->IsOpen() )
+ {
+ ULONG nFileSize = pStrm->Seek( STREAM_SEEK_TO_END );
+ nPages = ( nFileSize >= 512 ) ? ( nFileSize - 512 ) / nPageSize : 0;
+ pStrm->Seek( 0L );
+ }
+ else
+ nPages = 0;
+ bFile = TRUE;
+ SetError( bAccessDenied ? ERRCODE_IO_ACCESSDENIED : pStrm->GetError() );
+ return Good();
+}
+
+void StgCache::Close()
+{
+ if( bFile )
+ {
+ ((SvFileStream*) pStrm)->Close();
+ SetError( pStrm->GetError() );
+ }
+}
+
+// low level I/O
+
+BOOL StgCache::Read( INT32 nPage, void* pBuf, INT32 nPg )
+{
+ if( Good() )
+ {
+ ULONG nPos = Page2Pos( nPage );
+ ULONG nBytes = nPg * nPageSize;
+ // fixed address and size for the header
+ if( nPage == -1 )
+ nPos = 0L, nBytes = 512;
+ if( pStrm->Tell() != nPos )
+ {
+ ULONG nPhysPos = pStrm->Seek( nPos );
+#ifdef CHECK_DIRTY
+ if( nPhysPos != nPos )
+ ErrorBox( NULL, WB_OK, String("SO2: Seek failed") ).Execute();
+#endif
+ }
+ pStrm->Read( pBuf, nBytes );
+ SetError( pStrm->GetError() );
+ }
+ return Good();
+}
+
+BOOL StgCache::Write( INT32 nPage, void* pBuf, INT32 nPg )
+{
+ if( Good() )
+ {
+ ULONG nPos = Page2Pos( nPage );
+ ULONG nBytes = nPg * nPageSize;
+ // fixed address and size for the header
+ if( nPage == -1 )
+ nPos = 0L, nBytes = 512;
+ if( pStrm->Tell() != nPos )
+ {
+ ULONG nPhysPos = pStrm->Seek( nPos );
+#ifdef CHECK_DIRTY
+ if( nPhysPos != nPos )
+ ErrorBox( NULL, WB_OK, String("SO2: Seek failed") ).Execute();
+#endif
+ }
+ ULONG nRes = pStrm->Write( pBuf, nBytes );
+ if( nRes != nBytes )
+ SetError( SVSTREAM_WRITE_ERROR );
+ else
+ SetError( pStrm->GetError() );
+#ifdef READ_AFTER_WRITE
+ BYTE cBuf[ 512 ];
+ pStrm->Flush();
+ pStrm->Seek( nPos );
+ BOOL bRes = ( pStrm->Read( cBuf, 512 ) == 512 );
+ if( bRes )
+ bRes = !memcmp( cBuf, pBuf, 512 );
+ if( !bRes )
+ {
+ ErrorBox( NULL, WB_OK, String("SO2: Read after Write failed") ).Execute();
+ pStrm->SetError( SVSTREAM_WRITE_ERROR );
+ }
+#endif
+ }
+ return Good();
+}
+
+// set the file size in pages
+
+BOOL StgCache::SetSize( INT32 n )
+{
+ // Add the file header
+ INT32 nSize = n * nPageSize + 512;
+ pStrm->SetStreamSize( nSize );
+ SetError( pStrm->GetError() );
+ if( !nError )
+ nPages = n;
+ return Good();
+}
+
+void StgCache::SetError( ULONG n )
+{
+ if( n && !nError )
+ nError = n;
+}
+
+void StgCache::ResetError()
+{
+ nError = SVSTREAM_OK;
+ pStrm->ResetError();
+}
+
+void StgCache::MoveError( StorageBase& r )
+{
+ if( nError != SVSTREAM_OK )
+ {
+ r.SetError( nError );
+ ResetError();
+ }
+}
+
+// Utility functions
+
+INT32 StgCache::Page2Pos( INT32 nPage )
+{
+ if( nPage < 0 ) nPage = 0;
+ return( nPage * nPageSize ) + nPageSize;
+}
+
+INT32 StgCache::Pos2Page( INT32 nPos )
+{
+ return ( ( nPos + nPageSize - 1 ) / nPageSize ) * nPageSize - 1;
+}
+
diff --git a/sot/source/sdstor/stgcache.hxx b/sot/source/sdstor/stgcache.hxx
new file mode 100644
index 000000000000..c9a3bf032a3a
--- /dev/null
+++ b/sot/source/sdstor/stgcache.hxx
@@ -0,0 +1,164 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgcache.hxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifndef _STGCACHE_HXX
+#define _STGCACHE_HXX
+
+#ifndef _TOOLS_SOLAR_H
+#include <tools/solar.h>
+#endif
+#ifndef _TOOLS_STREAM_HXX
+#include <tools/stream.hxx>
+#endif
+
+#ifndef _STGELEM_HXX
+#include "stgelem.hxx"
+#endif
+
+
+class StgIo;
+class StgPage;
+class StgDirEntry;
+class StorageBase;
+
+class StgCache {
+ StgPage* pCur; // top of LRU list
+ StgPage* pElem1; // top of ordered list
+ ULONG nError; // error code
+ INT32 nPages; // size of data area in pages
+ USHORT nRef; // reference count
+ void * pLRUCache; // hash table of cached objects
+ short nPageSize; // page size of the file
+ void Erase( StgPage* ); // delete a cache element
+ void InsertToLRU( StgPage* ); // insert into LRU list
+ void InsertToOrdered( StgPage* ); // insert into ordered list
+ StgPage* Create( INT32 ); // create a cached page
+protected:
+ SvStream* pStrm; // physical stream
+ BOOL bMyStream; // TRUE: delete stream in dtor
+ BOOL bFile; // TRUE: file stream
+ INT32 Page2Pos( INT32 ); // page address --> file position
+ INT32 Pos2Page( INT32 ); // file position --> page address
+public:
+ StgCache();
+ ~StgCache();
+ void IncRef() { nRef++; }
+ USHORT DecRef() { return --nRef; }
+ void SetPhysPageSize( short );
+ INT32 GetPhysPages() { return nPages; }
+ short GetPhysPageSize() { return nPageSize; }
+ SvStream* GetStrm() { return pStrm; }
+ void SetStrm( SvStream*, BOOL );
+ BOOL IsWritable() { return pStrm->IsWritable(); }
+ BOOL Good() { return BOOL( nError == SVSTREAM_OK ); }
+ BOOL Bad() { return BOOL( nError != SVSTREAM_OK ); }
+ ULONG GetError() { return nError; }
+ void MoveError( StorageBase& );
+ void SetError( ULONG );
+ void ResetError();
+ BOOL Open( const String& rName, StreamMode );
+ void Close();
+ BOOL Read( INT32 nPage, void* pBuf, INT32 nPages );
+ BOOL Write( INT32 nPage, void* pBuf, INT32 nPages );
+ BOOL SetSize( INT32 nPages );
+ StgPage* Find( INT32 ); // find a cached page
+ StgPage* Get( INT32, BOOL ); // get a cached page
+ StgPage* Copy( INT32, INT32=STG_FREE ); // copy a page
+ BOOL Commit( StgDirEntry* = NULL ); // flush all pages
+ void Revert( StgDirEntry* = NULL ); // revert dirty pages
+ void Clear(); // clear the cache
+};
+
+class StgPage {
+ friend class StgCache;
+ StgCache* pCache; // the cache
+ StgPage *pNext1, *pLast1; // LRU chain
+ StgPage *pNext2, *pLast2; // ordered chain
+ StgDirEntry* pOwner; // owner
+ INT32 nPage; // page #
+ void* pData; // nPageSize characters
+ short nData; // size of this page
+ BOOL bDirty; // dirty flag
+ StgPage( StgCache*, short );
+ ~StgPage();
+public:
+ void SetDirty() { bDirty = TRUE; }
+ INT32 GetPage() { return nPage; }
+ void* GetData() { return pData; }
+ short GetSize() { return nData; }
+ void SetOwner( StgDirEntry* p ) { pOwner = p; }
+ // routines for accessing FAT pages
+ // Assume that the data is a FAT page and get/put FAT data.
+ INT32 GetPage( short nOff )
+ {
+ if( ( nOff >= (short) ( nData / sizeof( INT32 ) ) ) || nOff < 0 )
+ return -1;
+ INT32 n = ((INT32*) pData )[ nOff ];
+#ifdef __BIGENDIAN
+ return SWAPLONG(n);
+#else
+ return n;
+#endif
+ }
+ void SetPage( short, INT32 ); // put an element
+};
+
+#endif
diff --git a/sot/source/sdstor/stgdir.cxx b/sot/source/sdstor/stgdir.cxx
new file mode 100644
index 000000000000..c5f4db205021
--- /dev/null
+++ b/sot/source/sdstor/stgdir.cxx
@@ -0,0 +1,1032 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgdir.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <string.h> // memcpy()
+
+#include "stg.hxx"
+#include "stgelem.hxx"
+#include "stgcache.hxx"
+#include "stgstrms.hxx"
+#include "stgdir.hxx"
+#include "stgio.hxx"
+#pragma hdrstop
+
+//////////////////////////// class StgDirEntry /////////////////////////////
+
+// This class holds the dir entry data and maintains dirty flags for both
+// the entry and the data.
+
+// Transacted mode for streams: On the first write, a temp stream pTmpStrm
+// is created and operated on. A commit moves pTmpStrm to pCurStrm, which
+// is used for subsequent reads. A new write creates a new copy of pTmpStrm
+// based on pCurStrm. Reverting throws away pTmpStrm.
+// Transacted mode for storages: A copy of the dir ents is kept in aSave.
+// Committing means copying aEntry to aSave. Reverting means to copy aSave
+// to aEntry, delete newly created entries and to reactivate removed entries.
+
+// Problem der Implementation: Keine Hierarchischen commits. Daher nur
+// insgesamt transaktionsorientert oder direkt.
+
+StgDirEntry::StgDirEntry( const void* pFrom, BOOL * pbOk ) : StgAvlNode()
+{
+ *pbOk = aEntry.Load( pFrom );
+
+ InitMembers();
+}
+
+StgDirEntry::StgDirEntry( const StgEntry& r ) : StgAvlNode(), aEntry( r )
+{
+ InitMembers();
+}
+
+// Helper for all ctors
+
+void StgDirEntry::InitMembers()
+{
+ aSave = aEntry;
+ pUp =
+ pDown = NULL;
+ ppRoot = NULL;
+ pStgStrm = NULL;
+ pCurStrm =
+ pTmpStrm = NULL;
+ nPos =
+ nEntry =
+ nRefCnt = 0;
+ nMode = STREAM_READ;
+ bDirect = TRUE;
+ bInvalid =
+ bCreated =
+ bRenamed =
+ bRemoved =
+ bTemp =
+ bDirty =
+ bZombie = FALSE;
+}
+
+StgDirEntry::~StgDirEntry()
+{
+ Close();
+ delete pCurStrm;
+ delete pStgStrm;
+ delete pDown;
+}
+
+// Comparison function
+
+short StgDirEntry::Compare( const StgAvlNode* p ) const
+{
+ const StgDirEntry* pEntry = (const StgDirEntry*) p;
+ return aEntry.Compare( pEntry->aEntry );
+}
+
+// Enumerate the entry numbers.
+// n is incremented to show the total # of entries.
+// These number are later used as page numbers when storing
+// the TOC tree into the TOC stream. Remember that aSave is
+// stored, not aEntry.
+
+void StgDirEntry::Enum( INT32& n )
+{
+ INT32 nLeft = STG_FREE, nRight = STG_FREE, nDown = STG_FREE;
+ nEntry = n++;
+ if( pLeft )
+ {
+ ((StgDirEntry*) pLeft)->Enum( n ); nLeft = ((StgDirEntry*) pLeft)->nEntry;
+ }
+ if( pRight )
+ {
+ ((StgDirEntry*) pRight)->Enum( n ); nRight = ((StgDirEntry*) pRight)->nEntry;
+ }
+ if( pDown )
+ {
+ pDown->Enum( n ); nDown = pDown->nEntry;
+ }
+ aSave.SetLeaf( STG_LEFT, nLeft );
+ aSave.SetLeaf( STG_RIGHT, nRight );
+ aSave.SetLeaf( STG_CHILD, nDown );
+}
+
+// Delete all temporary entries before writing the TOC stream.
+// Until now Deltem is never called with bForce True
+
+void StgDirEntry::DelTemp( BOOL bForce )
+{
+ if( pLeft )
+ ((StgDirEntry*) pLeft)->DelTemp( FALSE );
+ if( pRight )
+ ((StgDirEntry*) pRight)->DelTemp( FALSE );
+ if( pDown )
+ {
+ // If the storage is dead, of course all elements are dead, too
+ if( bInvalid && aEntry.GetType() == STG_STORAGE )
+ bForce = TRUE;
+ pDown->DelTemp( bForce );
+ }
+ if( ( bForce || bInvalid )
+ && ( aEntry.GetType() != STG_ROOT ) /* && ( nRefCnt <= 1 ) */ )
+ {
+ Close();
+ if( pUp )
+ {
+ // this deletes the element if refcnt == 0!
+ BOOL bDel = nRefCnt == 0;
+ StgAvlNode::Remove( (StgAvlNode**) &pUp->pDown, this, bDel );
+ if( !bDel )
+ {
+ pLeft = pRight = pDown = 0;
+ bInvalid = bZombie = TRUE;
+ }
+ }
+ }
+}
+
+// Save the tree into the given dir stream
+
+BOOL StgDirEntry::Store( StgDirStrm& rStrm )
+{
+ void* pEntry = rStrm.GetEntry( nEntry, TRUE );
+ if( !pEntry )
+ return FALSE;
+ // Do not store the current (maybe not commited) entry
+ aSave.Store( pEntry );
+ if( pLeft )
+ if( !((StgDirEntry*) pLeft)->Store( rStrm ) )
+ return FALSE;
+ if( pRight )
+ if( !((StgDirEntry*) pRight)->Store( rStrm ) )
+ return FALSE;
+ if( pDown )
+ if( !pDown->Store( rStrm ) )
+ return FALSE;
+ return TRUE;
+}
+
+BOOL StgDirEntry::StoreStream( StgIo& rIo )
+{
+ if( aEntry.GetType() == STG_STREAM || aEntry.GetType() == STG_ROOT )
+ {
+ if( bInvalid )
+ {
+ // Delete the stream if needed
+ if( !pStgStrm )
+ {
+ OpenStream( rIo );
+ delete pStgStrm, pStgStrm = NULL;
+ }
+ else
+ pStgStrm->SetSize( 0 );
+ }
+ // or write the data stream
+ else if( !Tmp2Strm() )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// Save all dirty streams
+
+BOOL StgDirEntry::StoreStreams( StgIo& rIo )
+{
+ if( !StoreStream( rIo ) )
+ return FALSE;
+ if( pLeft )
+ if( !((StgDirEntry*) pLeft)->StoreStreams( rIo ) )
+ return FALSE;
+ if( pRight )
+ if( !((StgDirEntry*) pRight)->StoreStreams( rIo ) )
+ return FALSE;
+ if( pDown )
+ if( !pDown->StoreStreams( rIo ) )
+ return FALSE;
+ return TRUE;
+}
+
+// Revert all directory entries after failure to write the TOC stream
+
+void StgDirEntry::RevertAll()
+{
+ aEntry = aSave;
+ if( pLeft )
+ ((StgDirEntry*) pLeft)->RevertAll();
+ if( pRight )
+ ((StgDirEntry*) pRight)->RevertAll();
+ if( pDown )
+ pDown->RevertAll();
+}
+
+// Look if any element of the tree is dirty
+
+BOOL StgDirEntry::IsDirty()
+{
+ if( bDirty || bInvalid )
+ return TRUE;
+ if( pLeft && ((StgDirEntry*) pLeft)->IsDirty() )
+ return TRUE;
+ if( pRight && ((StgDirEntry*) pRight)->IsDirty() )
+ return TRUE;
+ if( pDown && pDown->IsDirty() )
+ return TRUE;
+ return FALSE;
+}
+
+// Set up a stream.
+
+void StgDirEntry::OpenStream( StgIo& rIo, BOOL bForceBig )
+{
+ short nThreshold = (USHORT) rIo.aHdr.GetThreshold();
+ delete pStgStrm;
+ if( !bForceBig && aEntry.GetSize() < (INT32) nThreshold )
+ pStgStrm = new StgSmallStrm( rIo, this );
+ else
+ pStgStrm = new StgDataStrm( rIo, this );
+ if( bInvalid && aEntry.GetSize() )
+ {
+ // This entry has invalid data, so delete that data
+ SetSize( 0L );
+// bRemoved = bInvalid = FALSE;
+ }
+ nPos = 0;
+}
+
+// Close the open stream without committing. If the entry is marked as
+// temporary, delete it.
+// Do not delete pCurStrm here!
+// (TLX:??? Zumindest pStgStrm muss deleted werden.)
+
+void StgDirEntry::Close()
+{
+ delete pTmpStrm;
+ pTmpStrm = NULL;
+// nRefCnt = 0;
+ bInvalid = bTemp;
+}
+
+// Get the current stream size
+
+INT32 StgDirEntry::GetSize()
+{
+ INT32 n;
+ if( pTmpStrm )
+ n = pTmpStrm->GetSize();
+ else if( pCurStrm )
+ n = pCurStrm->GetSize();
+ else n = aEntry.GetSize();
+ return n;
+}
+
+// Set the stream size. This means also creating a temp stream.
+
+BOOL StgDirEntry::SetSize( INT32 nNewSize )
+{
+ if( !bDirect && !pTmpStrm && !Strm2Tmp() )
+ return FALSE;
+ if( nNewSize < nPos )
+ nPos = nNewSize;
+ if( pTmpStrm )
+ {
+ pTmpStrm->SetSize( nNewSize );
+ pStgStrm->GetIo().SetError( pTmpStrm->GetError() );
+ return BOOL( pTmpStrm->GetError() == SVSTREAM_OK );
+ }
+ else
+ {
+ BOOL bRes = FALSE;
+ StgIo& rIo = pStgStrm->GetIo();
+ short nThreshold = (USHORT) rIo.aHdr.GetThreshold();
+ // ensure the correct storage stream!
+ StgStrm* pOld = NULL;
+ USHORT nOldSize = 0;
+ if( nNewSize > nThreshold && pStgStrm->IsSmallStrm() )
+ {
+ pOld = pStgStrm;
+ nOldSize = (USHORT) pOld->GetSize();
+ pStgStrm = new StgDataStrm( rIo, STG_EOF, 0 );
+ }
+ else if( nNewSize < nThreshold && !pStgStrm->IsSmallStrm() )
+ {
+ pOld = pStgStrm;
+ nOldSize = (USHORT) nNewSize;
+ pStgStrm = new StgSmallStrm( rIo, STG_EOF, 0 );
+ }
+ // now set the new size
+ if( pStgStrm->SetSize( nNewSize ) )
+ {
+ // did we create a new stream?
+ if( pOld )
+ {
+ // if so, we probably need to copy the old data
+ if( nOldSize )
+ {
+ void* pBuf = new BYTE[ nOldSize ];
+ pOld->Pos2Page( 0L );
+ pStgStrm->Pos2Page( 0L );
+ if( pOld->Read( pBuf, nOldSize )
+ && pStgStrm->Write( pBuf, nOldSize ) )
+ bRes = TRUE;
+ delete pBuf;
+ }
+ else
+ bRes = TRUE;
+ if( bRes )
+ {
+ pOld->SetSize( 0 );
+ delete pOld;
+ pStgStrm->Pos2Page( nPos );
+ pStgStrm->SetEntry( *this );
+ }
+ else
+ {
+ pStgStrm->SetSize( 0 );
+ delete pStgStrm;
+ pStgStrm = pOld;
+ }
+ }
+ else
+ {
+ pStgStrm->Pos2Page( nPos );
+ bRes = TRUE;
+ }
+ }
+ return bRes;
+ }
+}
+
+// Seek. On negative values, seek to EOF.
+
+INT32 StgDirEntry::Seek( INT32 nNew )
+{
+ if( pTmpStrm )
+ {
+ if( nNew < 0 )
+ nNew = pTmpStrm->GetSize();
+ nNew = pTmpStrm->Seek( nNew );
+ }
+ else if( pCurStrm )
+ {
+ if( nNew < 0 )
+ nNew = pCurStrm->GetSize();
+ nNew = pCurStrm->Seek( nNew );
+ }
+ else
+ {
+ INT32 nSize = aEntry.GetSize();
+ if( nNew < 0 )
+ nNew = nSize;
+ // enlarge?
+ if( nNew > nSize )
+ {
+ if( !SetSize( nNew ) )
+ return nPos;
+ else
+ return Seek( nNew );
+ }
+ pStgStrm->Pos2Page( nNew );
+ nNew = pStgStrm->GetPos();
+ }
+ return nPos = nNew;
+}
+
+// Read
+
+INT32 StgDirEntry::Read( void* p, INT32 nLen )
+{
+ if( nLen <= 0 )
+ return 0;
+ if( pTmpStrm )
+ nLen = pTmpStrm->Read( p, nLen );
+ else if( pCurStrm )
+ nLen = pCurStrm->Read( p, nLen );
+ else
+ nLen = pStgStrm->Read( p, nLen );
+ nPos += nLen;
+ return nLen;
+}
+
+// Write
+
+INT32 StgDirEntry::Write( const void* p, INT32 nLen )
+{
+ if( nLen <= 0 )
+ return 0;
+
+ // Was this stream committed internally and reopened in direct mode?
+ if( bDirect && ( pCurStrm || pTmpStrm ) && !Tmp2Strm() )
+ return 0;
+ // Is this stream opened in transacted mode? Do we have to make a copy?
+ if( !bDirect && !pTmpStrm && !Strm2Tmp() )
+ return 0;
+ if( pTmpStrm )
+ {
+ nLen = pTmpStrm->Write( p, nLen );
+ pStgStrm->GetIo().SetError( pTmpStrm->GetError() );
+ }
+ else
+ {
+ INT32 nNew = nPos + nLen;
+ if( nNew > pStgStrm->GetSize() )
+ {
+ if( !SetSize( nNew ) )
+ return 0L;
+ pStgStrm->Pos2Page( nPos );
+ }
+ nLen = pStgStrm->Write( p, nLen );
+ }
+ nPos += nLen;
+ return nLen;
+}
+
+// Copy the data of one entry into another entry.
+
+void StgDirEntry::Copy( StgDirEntry& rDest )
+{
+ INT32 n = GetSize();
+ if( rDest.SetSize( n ) && n )
+ {
+ void* p = new BYTE[ 4096 ];
+ Seek( 0L );
+ rDest.Seek( 0L );
+ while( n )
+ {
+ INT32 nn = n;
+ if( nn > 4096 )
+ nn = 4096;
+ if( Read( p, nn ) != nn )
+ break;
+ if( rDest.Write( p, nn ) != nn )
+ break;
+ n -= nn;
+ }
+ delete p;
+ }
+}
+
+// Commit this entry
+
+BOOL StgDirEntry::Commit()
+{
+ aSave = aEntry;
+ BOOL bRes = TRUE;
+ if( aEntry.GetType() == STG_STREAM )
+ {
+ if( pTmpStrm )
+ delete pCurStrm, pCurStrm = pTmpStrm, pTmpStrm = NULL;
+ if( bRemoved )
+ // Delete the stream if needed
+ if( pStgStrm )
+ pStgStrm->SetSize( 0 );
+ }
+ else if( aEntry.GetType() == STG_STORAGE && bDirect && bRes )
+ {
+ StgIterator aIter( *this );
+ for( StgDirEntry* p = aIter.First(); p && bRes; p = aIter.Next() )
+ bRes = p->Commit();
+ }
+ return bRes;
+}
+
+// Revert the entry
+
+BOOL StgDirEntry::Revert()
+{
+ aEntry = aSave;
+ switch( aEntry.GetType() )
+ {
+ case STG_STREAM:
+ if( pCurStrm )
+ delete pTmpStrm, pTmpStrm = pCurStrm, pCurStrm = NULL;
+ break;
+ case STG_STORAGE:
+ {
+ BOOL bSomeRenamed = FALSE;
+ StgIterator aIter( *this );
+ StgDirEntry* p = aIter.First();
+ while( p )
+ {
+ p->aEntry = p->aSave;
+ p->bDirty = FALSE;
+ bSomeRenamed = BOOL( bSomeRenamed | p->bRenamed );
+ // Remove any new entries
+ if( p->bCreated )
+ {
+ p->bCreated = FALSE;
+ p->Close();
+ p->bInvalid = TRUE;
+ }
+ // Reactivate any removed entries
+ else if( p->bRemoved )
+ p->bRemoved = p->bInvalid = p->bTemp = FALSE;
+ p = aIter.Next();
+ }
+ // Resort all renamed entries
+ if( bSomeRenamed )
+ {
+ StgIterator aIter( *this );
+ StgDirEntry* p = aIter.First();
+ while( p )
+ {
+ if( p->bRenamed )
+ {
+ StgAvlNode::Move
+ ( (StgAvlNode**) &p->pUp->pDown,
+ (StgAvlNode**) &p->pUp->pDown, p );
+ p->bRenamed = FALSE;
+ }
+ p = aIter.Next();
+ }
+ }
+ DelTemp( FALSE );
+ break;
+ }
+ }
+ return TRUE;
+}
+
+// Copy the stg stream to the temp stream
+
+BOOL StgDirEntry::Strm2Tmp()
+{
+ if( !pTmpStrm )
+ {
+ ULONG n = 0;
+ if( pCurStrm )
+ {
+ // It was already commited once
+ pTmpStrm = new StgTmpStrm;
+ if( pTmpStrm->GetError() == SVSTREAM_OK && pTmpStrm->Copy( *pCurStrm ) )
+ return TRUE;
+ n = 1; // indicates error
+ }
+ else
+ {
+ n = aEntry.GetSize();
+ pTmpStrm = new StgTmpStrm( n );
+ if( pTmpStrm->GetError() == SVSTREAM_OK )
+ {
+ if( n )
+ {
+ void* p = new BYTE[ 4096 ];
+ pStgStrm->Pos2Page( 0L );
+ while( n )
+ {
+ ULONG nn = n;
+ if( nn > 4096 )
+ nn = 4096;
+ if( (ULONG) pStgStrm->Read( p, nn ) != nn )
+ break;
+ if( pTmpStrm->Write( p, nn ) != nn )
+ break;
+ n -= nn;
+ }
+ delete p;
+ pStgStrm->Pos2Page( nPos );
+ pTmpStrm->Seek( nPos );
+ }
+ }
+ else
+ n = 1;
+ }
+ if( n )
+ {
+ pStgStrm->GetIo().SetError( pTmpStrm->GetError() );
+ delete pTmpStrm;
+ pTmpStrm = NULL;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+// Copy the temp stream to the stg stream during the final commit
+
+BOOL StgDirEntry::Tmp2Strm()
+{
+ // We did commit once, but have not written since then
+ if( !pTmpStrm )
+ pTmpStrm = pCurStrm, pCurStrm = NULL;
+ if( pTmpStrm )
+ {
+ ULONG n = pTmpStrm->GetSize();
+ StgStrm* pNewStrm;
+ StgIo& rIo = pStgStrm->GetIo();
+ ULONG nThreshold = (ULONG) rIo.aHdr.GetThreshold();
+ if( n < nThreshold )
+ pNewStrm = new StgSmallStrm( rIo, STG_EOF, 0 );
+ else
+ pNewStrm = new StgDataStrm( rIo, STG_EOF, 0 );
+ if( pNewStrm->SetSize( n ) )
+ {
+ void* p = new BYTE[ 4096 ];
+ pTmpStrm->Seek( 0L );
+ while( n )
+ {
+ ULONG nn = n;
+ if( nn > 4096 )
+ nn = 4096;
+ if( pTmpStrm->Read( p, nn ) != nn )
+ break;
+ if( (ULONG) pNewStrm->Write( p, nn ) != nn )
+ break;
+ n -= nn;
+ }
+ delete p;
+ if( n )
+ {
+ pTmpStrm->Seek( nPos );
+ pStgStrm->GetIo().SetError( pTmpStrm->GetError() );
+ delete pNewStrm;
+ return FALSE;
+ }
+ else
+ {
+ pStgStrm->SetSize( 0L );
+ delete pStgStrm;
+ pStgStrm = pNewStrm;
+ pNewStrm->SetEntry( *this );
+ pNewStrm->Pos2Page( nPos );
+ delete pTmpStrm;
+ delete pCurStrm;
+ pTmpStrm = pCurStrm = NULL;
+ aSave = aEntry;
+ }
+ }
+ }
+ return TRUE;
+}
+
+// Check if the given entry is contained in this entry
+
+BOOL StgDirEntry::IsContained( StgDirEntry* pStg )
+{
+ if( aEntry.GetType() == STG_STORAGE )
+ {
+ StgIterator aIter( *this );
+ StgDirEntry* p = aIter.First();
+ while( p )
+ {
+ if( !p->aEntry.Compare( pStg->aEntry ) )
+ return FALSE;
+ if( p->aEntry.GetType() == STG_STORAGE )
+ if( !p->IsContained( pStg ) )
+ return FALSE;
+ p = aIter.Next();
+ }
+ }
+ return TRUE;
+}
+
+// Invalidate all open entries by setting the RefCount to 0. If the bDel
+// flag is set, also set the invalid flag to indicate deletion during the
+// next dir stream flush.
+
+void StgDirEntry::Invalidate( BOOL bDel )
+{
+// nRefCnt = 0;
+ if( bDel )
+ bRemoved = bInvalid = TRUE;
+ switch( aEntry.GetType() )
+ {
+ case STG_STORAGE:
+ case STG_ROOT:
+ {
+ StgIterator aIter( *this );
+ for( StgDirEntry* p = aIter.First(); p; p = aIter.Next() )
+ p->Invalidate( bDel );
+ break;
+ }
+ }
+}
+
+///////////////////////////// class StgDirStrm ////////////////////////////
+
+// This specialized stream is the maintenance stream for the directory tree.
+
+StgDirStrm::StgDirStrm( StgIo& r )
+ : StgDataStrm( r, r.aHdr.GetTOCStart(), -1 )
+ , pRoot( NULL )
+ , nEntries( 0 )
+{
+ if( r.GetError() )
+ return;
+ nEntries = nPageSize / STGENTRY_SIZE;
+ if( nStart == STG_EOF )
+ {
+ StgEntry aRoot;
+ aRoot.Init();
+ aRoot.SetName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "Root Entry" ) ) );
+ aRoot.SetType( STG_ROOT );
+ pRoot = new StgDirEntry( aRoot );
+ pRoot->SetDirty();
+ }
+ else
+ {
+ // temporarily use this instance as owner, so
+ // the TOC pages can be removed.
+ pEntry = (StgDirEntry*) this; // just for a bit pattern
+ SetupEntry( 0, pRoot );
+ rIo.Revert( pEntry );
+ pEntry = NULL;
+ }
+}
+
+StgDirStrm::~StgDirStrm()
+{
+ delete pRoot;
+}
+
+// Recursively parse the directory tree during reading the TOC stream
+
+void StgDirStrm::SetupEntry( INT32 n, StgDirEntry* pUpper )
+{
+ void* p = ( n == STG_FREE ) ? NULL : GetEntry( n );
+ if( p )
+ {
+ BOOL bOk;
+ StgDirEntry* pCur = new StgDirEntry( p, &bOk );
+ if( !bOk )
+ {
+ delete pCur;
+ rIo.SetError( SVSTREAM_GENERALERROR );
+ // an error occured
+ return;
+ }
+
+ // better it is
+ if( !pUpper )
+ pCur->aEntry.SetType( STG_ROOT );
+
+ INT32 nLeft = pCur->aEntry.GetLeaf( STG_LEFT );
+ INT32 nRight = pCur->aEntry.GetLeaf( STG_RIGHT );
+ // substorage?
+ INT32 nLeaf = STG_FREE;
+ if( pCur->aEntry.GetType() == STG_STORAGE
+ || pCur->aEntry.GetType() == STG_ROOT )
+ nLeaf = pCur->aEntry.GetLeaf( STG_CHILD );
+ if( nLeaf != 0 && nLeft != 0 && nRight != 0 )
+ {
+ if( StgAvlNode::Insert
+ ( (StgAvlNode**) ( pUpper ? &pUpper->pDown : &pRoot ), pCur ) )
+ {
+ pCur->pUp = pUpper;
+ pCur->ppRoot = &pRoot;
+ }
+ else
+ {
+ rIo.SetError( SVSTREAM_CANNOT_MAKE );
+ delete pCur; pCur = NULL;
+ return;
+ }
+ SetupEntry( nLeft, pUpper );
+ SetupEntry( nRight, pUpper );
+ SetupEntry( nLeaf, pCur );
+ }
+ }
+}
+
+// Extend or shrink the directory stream.
+
+BOOL StgDirStrm::SetSize( INT32 nBytes )
+{
+ // Always allocate full pages
+ nBytes = ( ( nBytes + nPageSize - 1 ) / nPageSize ) * nPageSize;
+ return StgStrm::SetSize( nBytes );
+}
+
+// Save the TOC stream into a new substream after saving all data streams
+
+BOOL StgDirStrm::Store()
+{
+ if( !pRoot->IsDirty() )
+ return TRUE;
+ if( !pRoot->StoreStreams( rIo ) )
+ return FALSE;
+ // After writing all streams, the data FAT stream has changed,
+ // so we have to commit the root again
+ pRoot->Commit();
+ // We want a completely new stream, so fake an empty stream
+ INT32 nOldStart = nStart; // save for later deletion
+ INT32 nOldSize = nSize;
+ nStart = nPage = STG_EOF;
+ nSize = nPos = 0;
+ nOffset = 0;
+ // Delete all temporary entries
+ pRoot->DelTemp( FALSE );
+ // set the entry numbers
+ INT32 n = 0;
+ pRoot->Enum( n );
+ if( !SetSize( n * STGENTRY_SIZE ) )
+ {
+ nStart = nOldStart; nSize = nOldSize;
+ pRoot->RevertAll();
+ return FALSE;
+ }
+ // set up the cache elements for the new stream
+ if( !Copy( STG_FREE, nSize ) )
+ {
+ pRoot->RevertAll();
+ return FALSE;
+ }
+ // Write the data to the new stream
+ if( !pRoot->Store( *this ) )
+ {
+ pRoot->RevertAll();
+ return FALSE;
+ }
+ // fill any remaining entries with empty data
+ INT32 ne = nSize / STGENTRY_SIZE;
+ StgEntry aEmpty;
+ aEmpty.Init();
+ while( n < ne )
+ {
+ void* p = GetEntry( n++, TRUE );
+ if( !p )
+ {
+ pRoot->RevertAll();
+ return FALSE;
+ }
+ aEmpty.Store( p );
+ }
+ // Now we can release the old stream
+ pFat->FreePages( nOldStart, TRUE );
+ rIo.aHdr.SetTOCStart( nStart );
+ return TRUE;
+}
+
+// Get a dir entry.
+
+void* StgDirStrm::GetEntry( INT32 n, BOOL bDirty )
+{
+ n *= STGENTRY_SIZE;
+ if( n >= nSize )
+ return NULL;
+ return GetPtr( n, TRUE, bDirty );
+}
+
+// Find a dir entry.
+
+StgDirEntry* StgDirStrm::Find( StgDirEntry& rStg, const String& rName )
+{
+ if( rStg.pDown )
+ {
+ StgEntry aEntry;
+ aEntry.Init();
+ if( !aEntry.SetName( rName ) )
+ {
+ rIo.SetError( SVSTREAM_GENERALERROR );
+ return NULL;
+ }
+ // Look in the directory attached to the entry
+ StgDirEntry aTest( aEntry );
+ return (StgDirEntry*) rStg.pDown->Find( &aTest );
+ }
+ else
+ return NULL;
+}
+
+// Create a new entry.
+
+StgDirEntry* StgDirStrm::Create
+ ( StgDirEntry& rStg, const String& rName, StgEntryType eType )
+{
+ StgEntry aEntry;
+ aEntry.Init();
+ aEntry.SetType( eType );
+ if( !aEntry.SetName( rName ) )
+ {
+ rIo.SetError( SVSTREAM_GENERALERROR );
+ return NULL;
+ }
+ StgDirEntry* pRes = Find( rStg, rName );
+ if( pRes )
+ {
+ if( !pRes->bInvalid )
+ {
+ rIo.SetError( SVSTREAM_CANNOT_MAKE );
+ return NULL;
+ }
+ pRes->bInvalid =
+ pRes->bRemoved =
+ pRes->bTemp = FALSE;
+ pRes->bCreated =
+ pRes->bDirty = TRUE;
+ }
+ else
+ {
+ pRes = new StgDirEntry( aEntry );
+ if( StgAvlNode::Insert( (StgAvlNode**) &rStg.pDown, pRes ) )
+ {
+ pRes->pUp = &rStg;
+ pRes->ppRoot = &pRoot;
+ pRes->bCreated =
+ pRes->bDirty = TRUE;
+ }
+ else
+ {
+ rIo.SetError( SVSTREAM_CANNOT_MAKE );
+ delete pRes; pRes = NULL;
+ }
+ }
+ return pRes;
+}
+
+// Rename the given entry.
+
+BOOL StgDirStrm::Rename( StgDirEntry& rStg, const String& rOld, const String& rNew )
+{
+ StgDirEntry* p = Find( rStg, rOld );
+ if( p )
+ {
+
+ if( !StgAvlNode::Remove( (StgAvlNode**) &rStg.pDown, p, FALSE ) )
+ return FALSE;
+ p->aEntry.SetName( rNew );
+ if( !StgAvlNode::Insert( (StgAvlNode**) &rStg.pDown, p ) )
+ return FALSE;
+ p->bRenamed = p->bDirty = TRUE;
+ return TRUE;
+ }
+ else
+ {
+ rIo.SetError( SVSTREAM_FILE_NOT_FOUND );
+ return FALSE;
+ }
+}
+
+// Move the given entry to a different storage.
+
+BOOL StgDirStrm::Move( StgDirEntry& rStg1, StgDirEntry& rStg2, const String& rName )
+{
+ StgDirEntry* p = Find( rStg1, rName );
+ if( p )
+ {
+ if( !StgAvlNode::Move
+ ( (StgAvlNode**) &rStg1.pDown, (StgAvlNode**) &rStg2.pDown, p ) )
+ return FALSE;
+ p->bDirty = TRUE;
+ return TRUE;
+ }
+ else
+ {
+ rIo.SetError( SVSTREAM_FILE_NOT_FOUND );
+ return FALSE;
+ }
+}
+
diff --git a/sot/source/sdstor/stgdir.hxx b/sot/source/sdstor/stgdir.hxx
new file mode 100644
index 000000000000..44b1614a590f
--- /dev/null
+++ b/sot/source/sdstor/stgdir.hxx
@@ -0,0 +1,170 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgdir.hxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifndef _STGDIR_HXX
+#define _STGDIR_HXX
+
+#ifndef _STGAVL_HXX
+#include "stgavl.hxx"
+#endif
+#ifndef _STGELEM_HXX
+#include "stgelem.hxx"
+#endif
+#ifndef _STGSTRMS_HXX
+#include "stgstrms.hxx"
+#endif
+
+class StgIo;
+class StgEntry;
+class StgDirEntry;
+class StgDirStrm;
+
+class StgDirEntry : public StgAvlNode
+{
+ friend class StgIterator;
+ friend class StgDirStrm;
+ StgEntry aSave; // original dir entry
+ StgDirEntry* pUp; // parent directory
+ StgDirEntry* pDown; // child directory for storages
+ StgDirEntry** ppRoot; // root of TOC tree
+ StgStrm* pStgStrm; // storage stream
+ StgTmpStrm* pTmpStrm; // temporary stream
+ StgTmpStrm* pCurStrm; // temp stream after commit
+ INT32 nEntry; // entry # in TOC stream (temp)
+ INT32 nPos; // current position
+ BOOL bDirty; // dirty directory entry
+ BOOL bCreated; // newly created entry
+ BOOL bRemoved; // removed per Invalidate()
+ BOOL bRenamed; // renamed
+ void InitMembers(); // ctor helper
+ virtual short Compare( const StgAvlNode* ) const;
+ BOOL StoreStream( StgIo& ); // store the stream
+ BOOL StoreStreams( StgIo& ); // store all streams
+ void RevertAll(); // revert the whole tree
+ BOOL Strm2Tmp(); // copy stgstream to temp file
+ BOOL Tmp2Strm(); // copy temp file to stgstream
+public:
+ StgEntry aEntry; // entry data
+ INT32 nRefCnt; // reference count
+ StreamMode nMode; // open mode
+ BOOL bTemp; // TRUE: delete on dir flush
+ BOOL bDirect; // TRUE: direct mode
+ BOOL bZombie; // TRUE: Removed From StgIo
+ BOOL bInvalid; // TRUE: invalid entry
+ StgDirEntry( const void*, BOOL * pbOk );
+ StgDirEntry( const StgEntry& );
+ ~StgDirEntry();
+
+ void Invalidate( BOOL=FALSE ); // invalidate all open entries
+ void Enum( INT32& ); // enumerate entries for iteration
+ void DelTemp( BOOL ); // delete temporary entries
+ BOOL Store( StgDirStrm& ); // save entry into dir strm
+ BOOL IsContained( StgDirEntry* ); // check if subentry
+
+ void SetDirty() { bDirty = TRUE; }
+ BOOL IsDirty();
+ void ClearDirty();
+
+ BOOL Commit();
+ BOOL Revert();
+
+ void OpenStream( StgIo&, BOOL=FALSE ); // set up an approbiate stream
+ void Close();
+ INT32 GetSize();
+ BOOL SetSize( INT32 );
+ INT32 Seek( INT32 );
+ INT32 Tell() { return nPos; }
+ INT32 Read( void*, INT32 );
+ INT32 Write( const void*, INT32 );
+ void Copy( StgDirEntry& );
+};
+
+class StgDirStrm : public StgDataStrm
+{
+ friend class StgIterator;
+ StgDirEntry* pRoot; // root of dir tree
+ short nEntries; // entries per page
+ void SetupEntry( INT32, StgDirEntry* );
+public:
+ StgDirStrm( StgIo& );
+ ~StgDirStrm();
+ virtual BOOL SetSize( INT32 ); // change the size
+ BOOL Store();
+ void* GetEntry( INT32 n, BOOL=FALSE );// get an entry
+ StgDirEntry* GetRoot() { return pRoot; }
+ StgDirEntry* Find( StgDirEntry&, const String& );
+ StgDirEntry* Create( StgDirEntry&, const String&, StgEntryType );
+ BOOL Remove( StgDirEntry&, const String& );
+ BOOL Rename( StgDirEntry&, const String&, const String& );
+ BOOL Move( StgDirEntry&, StgDirEntry&, const String& );
+};
+
+class StgIterator : public StgAvlIterator
+{
+public:
+ StgIterator( StgDirEntry& rStg ) : StgAvlIterator( rStg.pDown ) {}
+ StgDirEntry* First() { return (StgDirEntry*) StgAvlIterator::First(); }
+ StgDirEntry* Next() { return (StgDirEntry*) StgAvlIterator::Next(); }
+ StgDirEntry* Last() { return (StgDirEntry*) StgAvlIterator::Last(); }
+ StgDirEntry* Prev() { return (StgDirEntry*) StgAvlIterator::Prev(); }
+};
+
+#endif
diff --git a/sot/source/sdstor/stgelem.cxx b/sot/source/sdstor/stgelem.cxx
new file mode 100644
index 000000000000..ef568aca861f
--- /dev/null
+++ b/sot/source/sdstor/stgelem.cxx
@@ -0,0 +1,433 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgelem.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <string.h> // memset(), memcpy()
+#include <tools/intn.hxx>
+#include "stg.hxx"
+#include "stgelem.hxx"
+#include "stgcache.hxx"
+#include "stgstrms.hxx"
+#include "stgdir.hxx"
+#include "stgio.hxx"
+
+#pragma hdrstop
+
+static BYTE cStgSignature[ 8 ] = { 0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1 };
+
+////////////////////////////// struct ClsId /////////////////////////////
+
+SvStream& operator >>( SvStream& r, ClsId& rId )
+{
+ r >> rId.n1
+ >> rId.n2
+ >> rId.n3
+ >> rId.n4
+ >> rId.n5
+ >> rId.n6
+ >> rId.n7
+ >> rId.n8
+ >> rId.n9
+ >> rId.n10
+ >> rId.n11;
+ return r;
+}
+
+SvStream& operator <<( SvStream& r, const ClsId& rId )
+{
+ return
+ r << (INT32) rId.n1
+ << (INT16) rId.n2
+ << (INT16) rId.n3
+ << (UINT8) rId.n4
+ << (UINT8) rId.n5
+ << (UINT8) rId.n6
+ << (UINT8) rId.n7
+ << (UINT8) rId.n8
+ << (UINT8) rId.n9
+ << (UINT8) rId.n10
+ << (UINT8) rId.n11;
+}
+
+///////////////////////////// class StgHeader ////////////////////////////
+
+StgHeader::StgHeader()
+{
+ memset( this, 0, sizeof( StgHeader ) );
+}
+
+void StgHeader::Init()
+{
+ memset( this, 0, sizeof( StgHeader ) );
+ memcpy( cSignature, cStgSignature, 8 );
+ nVersion = 0x0003003B;
+ nByteOrder = 0xFFFE;
+ nPageSize = 9; // 512 bytes
+ nDataPageSize = 6; // 64 bytes
+ nThreshold = 4096;
+ nDataFATSize = 0;
+ nMasterChain = STG_EOF;
+ SetTOCStart( STG_EOF );
+ SetDataFATStart( STG_EOF );
+ for( short i = 0; i < 109; i++ )
+ SetFATPage( i, STG_FREE );
+}
+
+BOOL StgHeader::Load( StgIo& rIo )
+{
+ SvStream& r = *rIo.GetStrm();
+ r.Seek( 0L );
+ r.Read( cSignature, 8 );
+ r >> aClsId // 08 Class ID
+ >> nVersion // 1A version number
+ >> nByteOrder // 1C Unicode byte order indicator
+ >> nPageSize // 1E 1 << nPageSize = block size
+ >> nDataPageSize; // 20 1 << this size == data block size
+ r.SeekRel( 10 );
+ r >> nFATSize // 2C total number of FAT pages
+ >> nTOCstrm // 30 starting page for the TOC stream
+ >> nReserved // 34
+ >> nThreshold // 38 minimum file size for big data
+ >> nDataFAT // 3C page # of 1st data FAT block
+ >> nDataFATSize // 40 # of data FATpages
+ >> nMasterChain // 44 chain to the next master block
+ >> nMaster; // 48 # of additional master blocks
+ for( short i = 0; i < 109; i++ )
+ r >> nMasterFAT[ i ];
+ return rIo.Good();
+}
+
+BOOL StgHeader::Store( StgIo& rIo )
+{
+ if( !bDirty )
+ return TRUE;
+ SvStream& r = *rIo.GetStrm();
+ r.Seek( 0L );
+ r.Write( cSignature, 8 + 16 );
+ r << nVersion // 1A version number
+ << nByteOrder // 1C Unicode byte order indicator
+ << nPageSize // 1E 1 << nPageSize = block size
+ << nDataPageSize // 20 1 << this size == data block size
+ << (INT32) 0 << (INT32) 0 << (INT16) 0
+ << nFATSize // 2C total number of FAT pages
+ << nTOCstrm // 30 starting page for the TOC stream
+ << nReserved // 34
+ << nThreshold // 38 minimum file size for big data
+ << nDataFAT // 3C page # of 1st data FAT block
+ << nDataFATSize // 40 # of data FAT pages
+ << nMasterChain // 44 chain to the next master block
+ << nMaster; // 48 # of additional master blocks
+ for( short i = 0; i < 109; i++ )
+ r << nMasterFAT[ i ];
+ bDirty = !rIo.Good();
+ return BOOL( !bDirty );
+}
+
+// Perform thorough checks also on unknown variables
+
+BOOL StgHeader::Check()
+{
+ return BOOL( memcmp( cSignature, cStgSignature, 8 ) == 0
+ && (short) ( nVersion >> 16 ) == 3 );
+}
+
+INT32 StgHeader::GetFATPage( short n ) const
+{
+ if( n >= 0 && n < 109 )
+ return nMasterFAT[ n ];
+ else
+ return STG_EOF;
+}
+
+void StgHeader::SetFATPage( short n, INT32 nb )
+{
+ if( n >= 0 && n < 109 )
+ {
+ if( nMasterFAT[ n ] != nb )
+ bDirty = TRUE, nMasterFAT[ n ] = nb;
+ }
+}
+
+void StgHeader::SetClassId( const ClsId& r )
+{
+ if( memcmp( &aClsId, &r, sizeof( ClsId ) ) )
+ bDirty = TRUE, memcpy( &aClsId, &r, sizeof( ClsId ) );
+}
+
+void StgHeader::SetTOCStart( INT32 n )
+{
+ if( n != nTOCstrm ) bDirty = TRUE, nTOCstrm = n;
+}
+
+void StgHeader::SetDataFATStart( INT32 n )
+{
+ if( n != nDataFAT ) bDirty = TRUE, nDataFAT = n;
+}
+
+void StgHeader::SetDataFATSize( INT32 n )
+{
+ if( n != nDataFATSize ) bDirty = TRUE, nDataFATSize = n;
+}
+
+void StgHeader::SetFATSize( INT32 n )
+{
+ if( n != nFATSize ) bDirty = TRUE, nFATSize = n;
+}
+
+void StgHeader::SetFATChain( INT32 n )
+{
+ if( n != nMasterChain )
+ bDirty = TRUE, nMasterChain = n;
+}
+
+void StgHeader::SetMasters( INT32 n )
+{
+ if( n != nMaster ) bDirty = TRUE, nMaster = n;
+}
+
+///////////////////////////// class StgEntry /////////////////////////////
+
+// This class is only a wrapper around teh dir entry structure
+// which retrieves and sets data.
+
+// The name must be smaller than 32 chars. Conversion into Unicode
+// is easy, since the 1st 256 characters of the Windows ANSI set
+// equal the 1st 256 Unicode characters.
+/*
+void ToUnicode_Impl( String& rName )
+{
+ rName.Erase( 32 );
+ rName.Convert( ::GetSystemCharSet(), CHARSET_ANSI );
+ // brute force is OK
+ BYTE* p = (BYTE*) rName.GetCharStr();
+ for( USHORT i = 0; i < rName.Len(); i++, p++ )
+ {
+ // check each character and substitute blanks for illegal ones
+ BYTE cChar = *p;
+ if( cChar == '!' || cChar == ':' || cChar == '\\' || cChar == '/' )
+ *p = ' ';
+ }
+}
+*/
+/*
+static void FromUnicode( String& rName )
+{
+ rName.Convert( CHARSET_ANSI, ::GetSystemCharSet() );
+}
+*/
+BOOL StgEntry::Init()
+{
+ memset( this, 0, sizeof (StgEntry) - sizeof( String ) );
+ SetLeaf( STG_LEFT, STG_FREE );
+ SetLeaf( STG_RIGHT, STG_FREE );
+ SetLeaf( STG_CHILD, STG_FREE );
+ SetLeaf( STG_DATA, STG_EOF );
+ return TRUE;
+}
+
+static International* pInter = 0;
+
+inline International& GetInternational()
+{
+ return pInter ? *pInter : *(pInter = new International);
+}
+
+BOOL StgEntry::SetName( const String& rName )
+{
+ const International& aInter = GetInternational();
+ // make upper case character in current language
+ aName = rName;
+ aName.Erase( 31 );
+ aInter.ToUpper( aName );
+ //ToUnicode_Impl( aNameStr );
+
+ int i;
+ for( i = 0; i < aName.Len() && i < 32; i++ )
+ nName[ i ] = rName.GetChar( i );
+ while( i < 32 )
+ nName[ i++ ] = 0;
+ nNameLen = ( aName.Len() + 1 ) << 1;
+ return TRUE;
+}
+
+INT32 StgEntry::GetLeaf( StgEntryRef eRef ) const
+{
+ INT32 n = -1;
+ switch( eRef )
+ {
+ case STG_LEFT: n = nLeft; break;
+ case STG_RIGHT: n = nRight; break;
+ case STG_CHILD: n = nChild; break;
+ case STG_DATA: n = nPage1; break;
+ }
+ return n;
+}
+
+void StgEntry::SetLeaf( StgEntryRef eRef, INT32 nPage )
+{
+ switch( eRef )
+ {
+ case STG_LEFT: nLeft = nPage; break;
+ case STG_RIGHT: nRight = nPage; break;
+ case STG_CHILD: nChild = nPage; break;
+ case STG_DATA: nPage1 = nPage; break;
+ }
+}
+
+const INT32* StgEntry::GetTime( StgEntryTime eTime ) const
+{
+ return( eTime == STG_MODIFIED ) ? nMtime : nAtime;
+}
+
+void StgEntry::SetTime( StgEntryTime eTime, INT32* pTime )
+{
+ if( eTime == STG_MODIFIED )
+ nMtime[ 0 ] = *pTime++, nMtime[ 1 ] = *pTime;
+ else
+ nAtime[ 0 ] = *pTime++, nAtime[ 1 ] = *pTime;
+}
+
+void StgEntry::SetClassId( const ClsId& r )
+{
+ memcpy( &aClsId, &r, sizeof( ClsId ) );
+}
+
+void StgEntry::GetName( String& rName ) const
+{
+ UINT16 n = nNameLen;
+ if( n )
+ n = ( n >> 1 ) - 1;
+ rName = String( nName, n );
+}
+
+// Compare two entries. Do this case-insensitive.
+
+short StgEntry::Compare( const StgEntry& r ) const
+{
+ /*
+ short nRes = r.nNameLen - nNameLen;
+ if( !nRes ) return strcmp( r.aName, aName );
+ else return nRes;
+ */
+ sal_Int32 nRes = r.nNameLen - nNameLen;
+ if( !nRes )
+ nRes = r.aName.CompareTo( aName );
+ return (short)nRes;
+ //return aName.CompareTo( r.aName );
+}
+
+// These load/store operations are a bit more complicated,
+// since they have to copy their contents into a packed structure.
+
+BOOL StgEntry::Load( const void* pFrom )
+{
+ SvMemoryStream r( (sal_Char*) pFrom, 128, STREAM_READ );
+ for( short i = 0; i < 32; i++ )
+ r >> nName[ i ]; // 00 name as WCHAR
+ r >> nNameLen // 40 size of name in bytes including 00H
+ >> cType // 42 entry type
+ >> cFlags // 43 0 or 1 (tree balance?)
+ >> nLeft // 44 left node entry
+ >> nRight // 48 right node entry
+ >> nChild // 4C 1st child entry if storage
+ >> aClsId // 50 class ID (optional)
+ >> nFlags // 60 state flags(?)
+ >> nMtime[ 0 ] // 64 modification time
+ >> nMtime[ 1 ] // 64 modification time
+ >> nAtime[ 0 ] // 6C creation and access time
+ >> nAtime[ 1 ] // 6C creation and access time
+ >> nPage1 // 74 starting block (either direct or translated)
+ >> nSize // 78 file size
+ >> nUnknown; // 7C unknown
+
+ UINT16 n = nNameLen;
+ if( n )
+ n = ( n >> 1 ) - 1;
+ if( n > 31 )
+ return FALSE;
+
+ aName = String( nName, n );
+ const International& aInter = GetInternational();
+ aInter.ToUpper( aName );
+ return TRUE;
+}
+
+void StgEntry::Store( void* pTo )
+{
+ SvMemoryStream r( (sal_Char *)pTo, 128, STREAM_WRITE );
+ for( short i = 0; i < 32; i++ )
+ r << nName[ i ]; // 00 name as WCHAR
+ r << nNameLen // 40 size of name in bytes including 00H
+ << cType // 42 entry type
+ << cFlags // 43 0 or 1 (tree balance?)
+ << nLeft // 44 left node entry
+ << nRight // 48 right node entry
+ << nChild // 4C 1st child entry if storage;
+ << aClsId // 50 class ID (optional)
+ << nFlags // 60 state flags(?)
+ << nMtime[ 0 ] // 64 modification time
+ << nMtime[ 1 ] // 64 modification time
+ << nAtime[ 0 ] // 6C creation and access time
+ << nAtime[ 1 ] // 6C creation and access time
+ << nPage1 // 74 starting block (either direct or translated)
+ << nSize // 78 file size
+ << nUnknown; // 7C unknown
+}
+
diff --git a/sot/source/sdstor/stgelem.hxx b/sot/source/sdstor/stgelem.hxx
new file mode 100644
index 000000000000..8273eb35b991
--- /dev/null
+++ b/sot/source/sdstor/stgelem.hxx
@@ -0,0 +1,204 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgelem.hxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+// This file reflects the structure of MS file elements.
+// It is very sensitive to alignment!
+
+#ifndef _STGELEM_HXX
+#define _STGELEM_HXX
+
+#ifndef _TOOLS_SOLAR_H
+#include <tools/solar.h>
+#endif
+
+class StgIo;
+class SvStream;
+class String;
+
+struct ClsId
+{
+ INT32 n1;
+ INT16 n2, n3;
+ UINT8 n4, n5, n6, n7, n8, n9, n10, n11;
+};
+
+SvStream& operator>>( SvStream&, ClsId& );
+SvStream& operator<<( SvStream&, const ClsId& );
+
+class StgHeader
+{
+ BYTE cSignature[ 8 ]; // 00 signature (see below)
+ ClsId aClsId; // 08 Class ID
+ INT32 nVersion; // 18 version number
+ UINT16 nByteOrder; // 1C Unicode byte order indicator
+ INT16 nPageSize; // 1E 1 << nPageSize = block size
+ INT16 nDataPageSize; // 20 1 << this size == data block size
+ BYTE bDirty; // 22 internal dirty flag
+ BYTE cReserved[ 9 ]; // 23
+ INT32 nFATSize; // 2C total number of FAT pages
+ INT32 nTOCstrm; // 30 starting page for the TOC stream
+ INT32 nReserved; // 34
+ INT32 nThreshold; // 38 minimum file size for big data
+ INT32 nDataFAT; // 3C page # of 1st data FAT block
+ INT32 nDataFATSize; // 40 # of data fat blocks
+ INT32 nMasterChain; // 44 chain to the next master block
+ INT32 nMaster; // 48 # of additional master blocks
+ INT32 nMasterFAT[ 109 ]; // 4C first 109 master FAT pages
+public:
+ StgHeader();
+ void Init(); // initialize the header
+ BOOL Load( StgIo& );
+ BOOL Store( StgIo& );
+ BOOL Check(); // check the signature and version
+ short GetByteOrder() const { return nByteOrder; }
+ INT32 GetTOCStart() const { return nTOCstrm; }
+ void SetTOCStart( INT32 n );
+ INT32 GetDataFATStart() const { return nDataFAT; }
+ void SetDataFATStart( INT32 n );
+ INT32 GetDataFATSize() const { return nDataFATSize; }
+ void SetDataFATSize( INT32 n );
+ INT32 GetThreshold() const { return nThreshold; }
+ short GetPageSize() const { return nPageSize; }
+ short GetDataPageSize() const { return nDataPageSize; }
+ INT32 GetFATSize() const { return nFATSize; }
+ void SetFATSize( INT32 n );
+ INT32 GetFATChain() const { return nMasterChain; }
+ void SetFATChain( INT32 n );
+ INT32 GetMasters() const { return nMaster; }
+ void SetMasters( INT32 n );
+ short GetFAT1Size() const { return 109; }
+ const ClsId& GetClassId() const { return aClsId; }
+ void SetClassId( const ClsId& );
+ INT32 GetFATPage( short ) const;
+ void SetFATPage( short, INT32 );
+};
+
+enum StgEntryType { // dir entry types:
+ STG_EMPTY = 0,
+ STG_STORAGE = 1,
+ STG_STREAM = 2,
+ STG_LOCKBYTES = 3,
+ STG_PROPERTY = 4,
+ STG_ROOT = 5
+};
+
+enum StgEntryRef { // reference blocks:
+ STG_LEFT = 0, // left
+ STG_RIGHT = 1, // right
+ STG_CHILD = 2, // child
+ STG_DATA = 3 // data start
+};
+
+enum StgEntryTime { // time codes:
+ STG_MODIFIED = 0, // last modification
+ STG_ACCESSED = 1 // last access
+};
+
+class StgStream;
+
+#define STGENTRY_SIZE 128
+
+class StgEntry { // directory enty
+ UINT16 nName[ 32 ]; // 00 name as WCHAR
+ INT16 nNameLen; // 40 size of name in bytes including 00H
+ BYTE cType; // 42 entry type
+ BYTE cFlags; // 43 0 or 1 (tree balance?)
+ INT32 nLeft; // 44 left node entry
+ INT32 nRight; // 48 right node entry
+ INT32 nChild; // 4C 1st child entry if storage
+ ClsId aClsId; // 50 class ID (optional)
+ INT32 nFlags; // 60 state flags(?)
+ INT32 nMtime[ 2 ]; // 64 modification time
+ INT32 nAtime[ 2 ]; // 6C creation and access time
+ INT32 nPage1; // 74 starting block (either direct or translated)
+ INT32 nSize; // 78 file size
+ INT32 nUnknown; // 7C unknown
+ String aName; // Name as Compare String (ascii, upper)
+public:
+ BOOL Init(); // initialize the data
+ BOOL SetName( const String& ); // store a name (ASCII, up to 32 chars)
+ void GetName( String& rName ) const;
+ // fill in the name
+ short Compare( const StgEntry& ) const; // compare two entries
+ BOOL Load( const void* );
+ void Store( void* );
+ StgEntryType GetType() const { return (StgEntryType) cType; }
+ INT32 GetStartPage() const { return nPage1; }
+ void SetType( StgEntryType t ) { cType = (BYTE) t; }
+ BYTE GetFlags() const { return cFlags; }
+ void SetFlags( BYTE c ) { cFlags = c; }
+ INT32 GetSize() const { return nSize; }
+ void SetSize( INT32 n ) { nSize = n; }
+ const ClsId& GetClassId() const { return aClsId; }
+ void SetClassId( const ClsId& );
+ INT32 GetLeaf( StgEntryRef ) const;
+ void SetLeaf( StgEntryRef, INT32 );
+ const INT32* GetTime( StgEntryTime ) const;
+ void SetTime( StgEntryTime, INT32* );
+};
+
+
+#define STG_FREE -1L // page is free
+#define STG_EOF -2L // page is last page in chain
+#define STG_FAT -3L // page is FAT page
+#define STG_MASTER -4L // page is master FAT page
+
+#endif
diff --git a/sot/source/sdstor/stgio.cxx b/sot/source/sdstor/stgio.cxx
new file mode 100644
index 000000000000..6b5e3e47758a
--- /dev/null
+++ b/sot/source/sdstor/stgio.cxx
@@ -0,0 +1,416 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgio.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:52 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include "stg.hxx"
+#include "stgelem.hxx"
+#include "stgcache.hxx"
+#include "stgstrms.hxx"
+#include "stgdir.hxx"
+#include "stgio.hxx"
+#pragma hdrstop
+
+///////////////////////////// class StgIo //////////////////////////////
+
+// This class holds the storage header and all internal streams.
+
+StgIo::StgIo() : StgCache()
+{
+ pTOC = NULL;
+ pDataFAT = NULL;
+ pDataStrm = NULL;
+ pFAT = NULL;
+ bCopied = FALSE;
+}
+
+StgIo::~StgIo()
+{
+ delete pTOC;
+ delete pDataFAT;
+ delete pDataStrm;
+ delete pFAT;
+}
+
+// Load the header. Do not set an error code if the header is invalid.
+
+BOOL StgIo::Load()
+{
+ if( pStrm )
+ {
+ if( aHdr.Load( *this ) )
+ if( aHdr.Check() )
+ SetupStreams();
+ else
+ return FALSE;
+ }
+ return Good();
+}
+
+// Set up an initial, empty storage
+
+BOOL StgIo::Init()
+{
+ aHdr.Init();
+ SetupStreams();
+ return CommitAll();
+}
+
+void StgIo::SetupStreams()
+{
+ delete pTOC;
+ delete pDataFAT;
+ delete pDataStrm;
+ delete pFAT;
+ pTOC = NULL;
+ pDataFAT = NULL;
+ pDataStrm = NULL;
+ pFAT = NULL;
+ ResetError();
+ SetPhysPageSize( 1 << aHdr.GetPageSize() );
+ pFAT = new StgFATStrm( *this );
+ pTOC = new StgDirStrm( *this );
+ if( !GetError() )
+ {
+ StgDirEntry* pRoot = pTOC->GetRoot();
+ if( pRoot )
+ {
+ pDataFAT = new StgDataStrm( *this, aHdr.GetDataFATStart(), -1 );
+ pDataStrm = new StgDataStrm( *this, pRoot );
+ pDataFAT->SetIncrement( 1 << aHdr.GetPageSize() );
+ pDataStrm->SetIncrement( GetDataPageSize() );
+ pDataStrm->SetEntry( *pRoot );
+ }
+ else
+ SetError( SVSTREAM_FILEFORMAT_ERROR );
+ }
+}
+
+// get the logical data page size
+
+short StgIo::GetDataPageSize()
+{
+ return 1 << aHdr.GetDataPageSize();
+}
+
+// Commit everything
+
+BOOL StgIo::CommitAll()
+{
+ // Store the data (all streams and the TOC)
+ if( pTOC->Store() )
+ {
+ if( Commit( NULL ) )
+ {
+ aHdr.SetDataFATStart( pDataFAT->GetStart() );
+ aHdr.SetDataFATSize( pDataFAT->GetPages() );
+ aHdr.SetTOCStart( pTOC->GetStart() );
+ if( aHdr.Store( *this ) )
+ {
+ pStrm->Flush();
+ ULONG n = pStrm->GetError();
+ SetError( n );
+#ifdef DBG_UTIL
+ if( n==0 ) ValidateFATs();
+#endif
+ return BOOL( n == 0 );
+ }
+ }
+ }
+ SetError( SVSTREAM_WRITE_ERROR );
+ return FALSE;
+}
+
+
+class EasyFat
+{
+ INT32 *pFat;
+ BOOL *pFree;
+ INT32 nPages;
+ INT32 nPageSize;
+
+public:
+ EasyFat( StgIo & rIo, StgStrm *pFatStream, INT32 nPSize );
+ ~EasyFat() { delete pFat; delete pFree; }
+ INT32 GetPageSize() { return nPageSize; }
+ INT32 Count() { return nPages; }
+ INT32 operator[]( INT32 nOffset ) { return pFat[ nOffset ]; }
+
+ ULONG Mark( INT32 nPage, INT32 nCount, INT32 nExpect );
+ BOOL HasUnrefChains();
+};
+
+EasyFat::EasyFat( StgIo& rIo, StgStrm* pFatStream, INT32 nPSize )
+{
+ nPages = pFatStream->GetSize() >> 2;
+ nPageSize = nPSize;
+ pFat = new INT32[ nPages ];
+ pFree = new BOOL[ nPages ];
+
+ StgPage *pPage;
+ INT32 nFatPageSize = 1 << rIo.aHdr.GetPageSize() - 2;
+
+ for( INT32 nPage = 0; nPage < nPages; nPage++ )
+ {
+ if( ! (nPage % nFatPageSize) )
+ {
+ pFatStream->Pos2Page( nPage << 2 );
+ INT32 nPhysPage = pFatStream->GetPage();
+ pPage = rIo.Get( nPhysPage, TRUE );
+ }
+
+ pFat[ nPage ] = pPage->GetPage( ( nPage % nFatPageSize ) );
+ pFree[ nPage ] = TRUE;
+ }
+}
+
+BOOL EasyFat::HasUnrefChains()
+{
+ for( INT32 nPage = 0; nPage < nPages; nPage++ )
+ {
+ if( pFree[ nPage ] && pFat[ nPage ] != -1 )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ULONG EasyFat::Mark( INT32 nPage, INT32 nCount, INT32 nExpect )
+{
+ if( nCount > 0 )
+ --nCount /= GetPageSize(), nCount++;
+
+ INT32 nCurPage = nPage;
+ while( nCount != 0 )
+ {
+ pFree[ nCurPage ] = FALSE;
+ nCurPage = pFat[ nCurPage ];
+ //Stream zu lang
+ if( nCurPage != nExpect && nCount == 1 )
+ return FAT_WRONGLENGTH;
+ //Stream zu kurz
+ if( nCurPage == nExpect && nCount != 1 && nCount != -1 )
+ return FAT_WRONGLENGTH;
+ // letzter Block bei Stream ohne Laenge
+ if( nCurPage == nExpect && nCount == -1 )
+ nCount = 1;
+ if( nCount != -1 )
+ nCount--;
+ // Naechster Block nicht in der FAT
+ if( nCount && ( nCurPage < 0 || nCurPage >= nPages ) )
+ return FAT_OUTOFBOUNDS;
+ }
+ return FAT_OK;
+}
+
+class Validator
+{
+ ULONG nError;
+
+ EasyFat aSmallFat;
+ EasyFat aFat;
+
+ StgIo &rIo;
+
+ ULONG ValidateMasterFATs();
+ ULONG ValidateDirectoryEntries();
+ ULONG FindUnrefedChains();
+ ULONG MarkAll( StgDirEntry *pEntry );
+
+public:
+
+ Validator( StgIo &rIo );
+ BOOL IsError() { return nError != 0; }
+};
+
+Validator::Validator( StgIo &rIoP )
+ : aSmallFat( rIoP, rIoP.pDataFAT, 1 << rIoP.aHdr.GetDataPageSize() ),
+ aFat( rIoP, rIoP.pFAT, 1 << rIoP.aHdr.GetPageSize() ),
+ rIo( rIoP )
+{
+ ULONG nErr = nError = FAT_OK;
+
+ if( ( nErr = ValidateMasterFATs() ) != FAT_OK )
+ nError = nErr;
+ else if( ( nErr = ValidateDirectoryEntries() ) != FAT_OK )
+ nError = nErr;
+ else if( ( nErr = FindUnrefedChains()) != FAT_OK )
+ nError = nErr;
+}
+
+ULONG Validator::ValidateMasterFATs()
+{
+ INT32 nCount = rIo.aHdr.GetFATSize();
+ ULONG nErr;
+ for( INT32 i = 0; i < nCount; i++ )
+ {
+ if( ( nErr = aFat.Mark(
+ rIo.pFAT->GetPage( i, FALSE ), aFat.GetPageSize(), -3 ))
+ != FAT_OK )
+ return nErr;
+ }
+ if( rIo.aHdr.GetMasters() )
+ if( ( nErr = aFat.Mark(
+ rIo.aHdr.GetFATChain( ), aFat.GetPageSize(), -4 )) != FAT_OK )
+ return nErr;
+ return FAT_OK;
+}
+
+ULONG Validator::MarkAll( StgDirEntry *pEntry )
+{
+ StgIterator aIter( *pEntry );
+ ULONG nErr = FAT_OK;
+ for( StgDirEntry* p = aIter.First(); p ; p = aIter.Next() )
+ {
+ if( p->aEntry.GetType() == STG_STORAGE )
+ {
+ nErr = MarkAll( p );
+ if( nErr != FAT_OK )
+ return nErr;
+ }
+ else
+ {
+ INT32 nSize = p->aEntry.GetSize();
+ if( nSize < rIo.aHdr.GetThreshold() )
+ nErr = aSmallFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
+ else
+ nErr = aFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
+ if( nErr != FAT_OK )
+ return nErr;
+ }
+ }
+ return FAT_OK;
+}
+
+ULONG Validator::ValidateDirectoryEntries()
+{
+ // Normale DirEntries
+ ULONG nErr = MarkAll( rIo.pTOC->GetRoot() );
+ if( nErr != FAT_OK )
+ return nErr;
+ // Small Data
+ nErr = aFat.Mark( rIo.pTOC->GetRoot()->aEntry.GetStartPage(),
+ rIo.pTOC->GetRoot()->aEntry.GetSize(), -2 );
+ if( nErr != FAT_OK )
+ return nErr;
+ // Small Data FAT
+ nErr = aFat.Mark(
+ rIo.aHdr.GetDataFATStart(),
+ rIo.aHdr.GetDataFATSize() * aFat.GetPageSize(), -2 );
+ if( nErr != FAT_OK )
+ return nErr;
+ // TOC
+ nErr = aFat.Mark(
+ rIo.aHdr.GetTOCStart(), -1, -2 );
+ return nErr;
+}
+
+ULONG Validator::FindUnrefedChains()
+{
+ if( aSmallFat.HasUnrefChains() ||
+ aFat.HasUnrefChains() )
+ return FAT_UNREFCHAIN;
+ else
+ return FAT_OK;
+}
+
+Link StgIo::aErrorLink;
+
+void StgIo::SetErrorLink( const Link& rLink )
+{
+ aErrorLink = rLink;
+}
+
+ULONG StgIo::ValidateFATs()
+{
+ if( bFile )
+ {
+ Validator *pV = new Validator( *this );
+ BOOL bRet1 = !pV->IsError(), bRet2 = TRUE ;
+ delete pV;
+ SvFileStream *pFileStrm = ( SvFileStream *) GetStrm();
+ StgIo aIo;
+ if( aIo.Open( pFileStrm->GetFileName(),
+ STREAM_READ | STREAM_SHARE_DENYNONE) &&
+ aIo.Load() )
+ {
+ pV = new Validator( aIo );
+ bRet2 = !pV->IsError();
+ delete pV;
+ }
+
+ ULONG nErr;
+ if( bRet1 != bRet2 )
+ nErr = bRet1 ? FAT_ONFILEERROR : FAT_INMEMORYERROR;
+ else nErr = bRet1 ? FAT_OK : FAT_BOTHERROR;
+ if( nErr != FAT_OK && !bCopied )
+ {
+ StgLinkArg aArg;
+ aArg.aFile = pFileStrm->GetFileName();
+ aArg.nErr = nErr;
+ aErrorLink.Call( &aArg );
+ bCopied = TRUE;
+ }
+// DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
+ return nErr;
+ }
+// DBG_ERROR("Validiere nicht (kein FileStorage)");
+ return FAT_OK;
+}
+
+
diff --git a/sot/source/sdstor/stgio.hxx b/sot/source/sdstor/stgio.hxx
new file mode 100644
index 000000000000..3418cd013415
--- /dev/null
+++ b/sot/source/sdstor/stgio.hxx
@@ -0,0 +1,121 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgio.hxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:52 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifndef _STGIO_HXX
+#define _STGIO_HXX
+
+#ifndef _STGCACHE_HXX
+#include <stgcache.hxx>
+#endif
+#ifndef _STGELEM_HXX
+#include <stgelem.hxx>
+#endif
+#ifndef _TOOLS_STRING_HXX
+#include <tools/string.hxx>
+#endif
+
+class StgFATStrm;
+class StgDataStrm;
+class StgDirStrm;
+class String;
+
+enum FAT_ERROR
+{
+ FAT_OK,
+ FAT_WRONGLENGTH,
+ FAT_UNREFCHAIN,
+ FAT_OVERWRITE,
+ FAT_OUTOFBOUNDS,
+
+ FAT_INMEMORYERROR,
+ FAT_ONFILEERROR,
+ FAT_BOTHERROR
+};
+
+struct StgLinkArg
+{
+ String aFile;
+ ULONG nErr;
+};
+
+class StgIo : public StgCache {
+ void SetupStreams(); // load all internal streams
+ BOOL bCopied;
+public:
+ StgIo();
+ ~StgIo();
+ StgHeader aHdr; // storage file header
+ StgFATStrm* pFAT; // FAT stream
+ StgDirStrm* pTOC; // TOC stream
+ StgDataStrm* pDataFAT; // small data FAT stream
+ StgDataStrm* pDataStrm; // small data stream
+ short GetDataPageSize(); // get the logical data page size
+ BOOL Load(); // load a storage file
+ BOOL Init(); // set up an empty file
+ BOOL CommitAll(); // commit everything (root commit)
+
+ static Link aErrorLink;
+ static void SetErrorLink( const Link& );
+ static const Link& GetErrorLink() { return aErrorLink; }
+ ULONG ValidateFATs( );
+};
+
+#endif
diff --git a/sot/source/sdstor/stgole.cxx b/sot/source/sdstor/stgole.cxx
new file mode 100644
index 000000000000..6551754d3c00
--- /dev/null
+++ b/sot/source/sdstor/stgole.cxx
@@ -0,0 +1,255 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgole.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:52 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include "rtl/string.h"
+#include "rtl/string.h"
+#include "stgole.hxx"
+#include "storinfo.hxx" // Read/WriteClipboardFormat()
+#pragma hdrstop
+
+///////////////////////// class StgInternalStream ////////////////////////
+
+StgInternalStream::StgInternalStream
+ ( Storage& rStg, const String& rName, BOOL bWr )
+{
+ bIsWritable = TRUE;
+ USHORT nMode = bWr
+ ? STREAM_WRITE | STREAM_SHARE_DENYALL
+ : STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE;
+ pStrm = rStg.OpenStream( rName, nMode );
+ // set the error code right here in the stream
+ SetError( rStg.GetError() );
+ SetBufferSize( 1024 );
+}
+
+StgInternalStream::~StgInternalStream()
+{
+ delete pStrm;
+}
+
+ULONG StgInternalStream::GetData( void* pData, ULONG nSize )
+{
+ if( pStrm )
+ {
+ nSize = pStrm->Read( pData, nSize );
+ SetError( pStrm->GetError() );
+ return nSize;
+ }
+ else
+ return 0;
+}
+
+ULONG StgInternalStream::PutData( const void* pData, ULONG nSize )
+{
+ if( pStrm )
+ {
+ nSize = pStrm->Write( pData, nSize );
+ SetError( pStrm->GetError() );
+ return nSize;
+ }
+ else
+ return 0;
+}
+
+ULONG StgInternalStream::SeekPos( ULONG nPos )
+{
+ return pStrm ? pStrm->Seek( nPos ) : 0;
+}
+
+void StgInternalStream::FlushData()
+{
+ if( pStrm )
+ {
+ pStrm->Flush();
+ SetError( pStrm->GetError() );
+ }
+}
+
+void StgInternalStream::Commit()
+{
+ Flush();
+ pStrm->Commit();
+}
+
+///////////////////////// class StgCompObjStream /////////////////////////
+
+StgCompObjStream::StgCompObjStream( Storage& rStg, BOOL bWr )
+ : StgInternalStream( rStg, String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "\1CompObj" ) ), bWr )
+{
+ memset( &aClsId, 0, sizeof( ClsId ) );
+ nCbFormat = 0;
+}
+
+BOOL StgCompObjStream::Load()
+{
+ memset( &aClsId, 0, sizeof( ClsId ) );
+ nCbFormat = 0;
+ aUserName.Erase();
+ if( GetError() != SVSTREAM_OK )
+ return FALSE;
+ Seek( 8L ); // skip the first part
+ INT32 nMarker = 0;
+ *this >> nMarker;
+ if( nMarker == -1L )
+ {
+ *this >> aClsId;
+ INT32 nLen1 = 0;
+ *this >> nLen1;
+ sal_Char* p = new sal_Char[ (USHORT) nLen1 ];
+ if( Read( p, nLen1 ) == (ULONG) nLen1 )
+ {
+ aUserName = String( p, gsl_getSystemTextEncoding() );
+/* // Now we can read the CB format
+ INT32 nLen2 = 0;
+ *this >> nLen2;
+ if( nLen2 > 0 )
+ {
+ // get a string name
+ if( nLen2 > nLen1 )
+ delete p, p = new char[ nLen2 ];
+ if( Read( p, nLen2 ) == (ULONG) nLen2 )
+ nCbFormat = Exchange::RegisterFormatName( String( p ) );
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ }
+ else if( nLen2 == -1L )
+ // Windows clipboard format
+ *this >> nCbFormat;
+ else
+ // unknown identifier
+ SetError( SVSTREAM_GENERALERROR );
+*/
+ nCbFormat = ReadClipboardFormat( *this );
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ delete p;
+ }
+ return BOOL( GetError() == SVSTREAM_OK );
+}
+
+BOOL StgCompObjStream::Store()
+{
+ if( GetError() != SVSTREAM_OK )
+ return FALSE;
+ Seek( 0L );
+ ByteString aAsciiUserName( aUserName, RTL_TEXTENCODING_ASCII_US );
+ *this << (INT16) 1 // Version?
+ << (INT16) 0xFFFE // Byte Order Indicator
+ << (INT32) 0x0A03 // Windows 3.10
+ << (INT32) -1L
+ << aClsId // Class ID
+ << (INT32) (aAsciiUserName.Len() + 1)
+ << (const char *)aAsciiUserName.GetBuffer()
+ << (UINT8) 0; // string terminator
+/* // determine the clipboard format string
+ String aCbFmt;
+ if( nCbFormat > FORMAT_GDIMETAFILE )
+ aCbFmt = Exchange::GetFormatName( nCbFormat );
+ if( aCbFmt.Len() )
+ *this << (INT32) aCbFmt.Len() + 1
+ << (const char*) aCbFmt
+ << (UINT8) 0;
+ else if( nCbFormat )
+ *this << (INT32) -1 // for Windows
+ << (INT32) nCbFormat;
+ else
+ *this << (INT32) 0; // no clipboard format
+*/
+ WriteClipboardFormat( *this, nCbFormat );
+ *this << (INT32) 0; // terminator
+ Commit();
+ return BOOL( GetError() == SVSTREAM_OK );
+}
+
+/////////////////////////// class StgOleStream ///////////////////////////
+
+StgOleStream::StgOleStream( Storage& rStg, BOOL bWr )
+ : StgInternalStream( rStg, String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "\1Ole" ) ), bWr )
+{
+ nFlags = 0;
+}
+
+BOOL StgOleStream::Load()
+{
+ nFlags = 0;
+ if( GetError() != SVSTREAM_OK )
+ return FALSE;
+ INT32 nVersion = 0;
+ Seek( 0L );
+ *this >> nVersion >> nFlags;
+ return BOOL( GetError() == SVSTREAM_OK );
+}
+
+BOOL StgOleStream::Store()
+{
+ if( GetError() != SVSTREAM_OK )
+ return FALSE;
+ Seek( 0L );
+ *this << (INT32) 0x02000001 // OLE version, format
+ << (INT32) nFlags // Object flags
+ << (INT32) 0 // Update Options
+ << (INT32) 0 // reserved
+ << (INT32) 0; // Moniker 1
+ Commit();
+ return BOOL( GetError() == SVSTREAM_OK );
+}
+
diff --git a/sot/source/sdstor/stgole.hxx b/sot/source/sdstor/stgole.hxx
new file mode 100644
index 000000000000..7356bccff445
--- /dev/null
+++ b/sot/source/sdstor/stgole.hxx
@@ -0,0 +1,111 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgole.hxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:52 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifndef _SDSTOR_STGOLE_HXX
+#define _SDSTOR_STGOLE_HXX
+
+#include <string.h> // memset()
+
+#include "stg.hxx"
+#include "stgelem.hxx"
+
+class StgInternalStream : public SvStream
+{
+ StorageStream* pStrm;
+ virtual ULONG GetData( void* pData, ULONG nSize );
+ virtual ULONG PutData( const void* pData, ULONG nSize );
+ virtual ULONG SeekPos( ULONG nPos );
+ virtual void FlushData();
+public:
+ StgInternalStream( Storage&, const String&, BOOL );
+ ~StgInternalStream();
+ void Commit();
+};
+
+// standard stream "\1CompObj"
+
+class StgCompObjStream : public StgInternalStream
+{
+ ClsId aClsId;
+ String aUserName;
+ ULONG nCbFormat;
+public:
+ StgCompObjStream( Storage&, BOOL );
+ ClsId& GetClsId() { return aClsId; }
+ String& GetUserName() { return aUserName; }
+ ULONG& GetCbFormat() { return nCbFormat; }
+ BOOL Load();
+ BOOL Store();
+};
+
+// standard stream "\1Ole"
+
+class StgOleStream : public StgInternalStream
+{
+ ULONG nFlags;
+public:
+ StgOleStream( Storage&, BOOL );
+ ULONG& GetFlags() { return nFlags; }
+ BOOL Load();
+ BOOL Store();
+};
+
+#endif
diff --git a/sot/source/sdstor/stgstrms.cxx b/sot/source/sdstor/stgstrms.cxx
new file mode 100644
index 000000000000..e295edc92ac6
--- /dev/null
+++ b/sot/source/sdstor/stgstrms.cxx
@@ -0,0 +1,1268 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgstrms.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:52 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <string.h> // memcpy()
+
+#ifndef _TOOLS_FSYS_HXX
+#include <tools/fsys.hxx>
+#endif
+#include <tools/debug.hxx>
+
+#include "stg.hxx"
+#include "stgelem.hxx"
+#include "stgcache.hxx"
+#include "stgstrms.hxx"
+#include "stgdir.hxx"
+#include "stgio.hxx"
+#pragma hdrstop
+
+#if defined(W31)
+ #include <tools/svwin.h>
+ #define memcpy hmemcpy
+ #define __HUGE _huge
+#else
+ #define __HUGE
+#endif
+
+///////////////////////////// class StgFAT ///////////////////////////////
+
+// The FAT class performs FAT operations on an underlying storage stream.
+// This stream is either the master FAT stream (m == TRUE ) or a normal
+// storage stream, which then holds the FAT for small data allocations.
+
+StgFAT::StgFAT( StgStrm& r, BOOL m ) : rStrm( r )
+{
+ bPhys = m;
+ nPageSize = rStrm.GetIo().GetPhysPageSize();
+ nEntries = nPageSize >> 2;
+ nOffset = 0;
+ nMaxPage = 0;
+ nLimit = 0;
+}
+
+// Retrieve the physical page for a given byte offset.
+
+StgPage* StgFAT::GetPhysPage( INT32 nByteOff )
+{
+ StgPage* pPg = NULL;
+ // Position within the underlying stream
+ // use the Pos2Page() method of the stream
+ if( rStrm.Pos2Page( nByteOff ) )
+ {
+ nOffset = rStrm.GetOffset();
+ INT32 nPhysPage = rStrm.GetPage();
+ // get the physical page (must be present)
+ pPg = rStrm.GetIo().Get( nPhysPage, TRUE );
+ }
+ return pPg;
+}
+
+// Get the follow page for a certain FAT page.
+
+INT32 StgFAT::GetNextPage( INT32 nPg )
+{
+ if( nPg >= 0 )
+ {
+ StgPage* pPg = GetPhysPage( nPg << 2 );
+ nPg = pPg ? pPg->GetPage( nOffset >> 2 ) : STG_EOF;
+ }
+ return nPg;
+}
+
+// Find the best fit block for the given size. Return
+// the starting block and its size or STG_EOF and 0.
+// nLastPage is a stopper which tells the current
+// underlying stream size. It is treated as a recommendation
+// to abort the search to inhibit excessive file growth.
+
+INT32 StgFAT::FindBlock( INT32& nPgs )
+{
+ INT32 nMinStart = STG_EOF, nMinLen = 0;
+ INT32 nMaxStart = STG_EOF, nMaxLen = 0x7FFFFFFFL;
+ INT32 nTmpStart = STG_EOF, nTmpLen = 0;
+ INT32 nPages = rStrm.GetSize() >> 2;
+ BOOL bFound = FALSE;
+ StgPage* pPg;
+ short nEntry = 0;
+ for( INT32 i = 0; i < nPages; i++, nEntry++ )
+ {
+ if( !( nEntry % nEntries ) )
+ {
+ // load the next page for that stream
+ nEntry = 0;
+ pPg = GetPhysPage( i << 2 );
+ if( !pPg )
+ return STG_EOF;
+ }
+ INT32 nCur = pPg->GetPage( nEntry );
+ if( nCur == STG_FREE )
+ {
+ // count the size of this area
+ if( nTmpLen )
+ nTmpLen++;
+ else
+ nTmpStart = i,
+ nTmpLen = 1;
+ if( nTmpLen == nPgs
+ // If we already did find a block, stop when reaching the limit
+ || ( bFound && ( nEntry >= nLimit ) ) )
+ break;
+ }
+ else if( nTmpLen )
+ {
+ if( nTmpLen > nPgs && nTmpLen < nMaxLen )
+ // block > requested size
+ nMaxLen = nTmpLen, nMaxStart = nTmpStart, bFound = TRUE;
+ else if( nTmpLen >= nMinLen )
+ {
+ // block < requested size
+ nMinLen = nTmpLen, nMinStart = nTmpStart;
+ bFound = TRUE;
+ if( nTmpLen == nPgs )
+ break;
+ }
+ nTmpStart = STG_EOF;
+ nTmpLen = 0;
+ }
+ }
+ // Determine which block to use.
+ if( nTmpLen )
+ {
+ if( nTmpLen > nPgs && nTmpLen < nMaxLen )
+ // block > requested size
+ nMaxLen = nTmpLen, nMaxStart = nTmpStart;
+ else if( nTmpLen >= nMinLen )
+ // block < requested size
+ nMinLen = nTmpLen, nMinStart = nTmpStart;
+ }
+ if( nMinStart != STG_EOF && nMaxStart != STG_EOF )
+ {
+ // two areas found; return the best fit area
+ INT32 nMinDiff = nPgs - nMinLen;
+ INT32 nMaxDiff = nMaxLen - nPgs;
+ if( nMinDiff > nMaxDiff )
+ nMinStart = STG_EOF;
+ }
+ if( nMinStart != STG_EOF )
+ {
+ nPgs = nMinLen; return nMinStart;
+ }
+ else
+ {
+ return nMaxStart;
+ }
+}
+
+// Set up the consecutive chain for a given block.
+
+BOOL StgFAT::MakeChain( INT32 nStart, INT32 nPgs )
+{
+ INT32 nPos = nStart << 2;
+ StgPage* pPg = GetPhysPage( nPos );
+ if( !pPg || !nPgs )
+ return FALSE;
+ while( --nPgs )
+ {
+ if( nOffset >= nPageSize )
+ {
+ pPg = GetPhysPage( nPos );
+ if( !pPg )
+ return FALSE;
+ }
+ pPg->SetPage( nOffset >> 2, ++nStart );
+ nOffset += 4;
+ nPos += 4;
+ }
+ if( nOffset >= nPageSize )
+ {
+ pPg = GetPhysPage( nPos );
+ if( !pPg )
+ return FALSE;
+ }
+ pPg->SetPage( nOffset >> 2, STG_EOF );
+ return TRUE;
+}
+
+// Allocate a block of data from the given page number on.
+// It the page number is != STG_EOF, chain the block.
+
+INT32 StgFAT::AllocPages( INT32 nBgn, INT32 nPgs )
+{
+ INT32 nOrig = nBgn;
+ INT32 nLast = nBgn;
+ INT32 nBegin, nAlloc;
+ INT32 nPages = rStrm.GetSize() >> 2;
+ short nPasses = 0;
+ // allow for two passes
+ while( nPasses < 2 )
+ {
+ // try to satisfy the request from the pool of free pages
+ while( nPgs )
+ {
+ nAlloc = nPgs;
+ nBegin = FindBlock( nAlloc );
+ // no more blocks left in present alloc chain
+ if( nBegin == STG_EOF )
+ break;
+ if( ( nBegin + nAlloc ) > nMaxPage )
+ nMaxPage = nBegin + nAlloc;
+ if( !MakeChain( nBegin, nAlloc ) )
+ return STG_EOF;
+ if( nOrig == STG_EOF )
+ nOrig = nBegin;
+ else
+ {
+ // Patch the chain
+ StgPage* pPg = GetPhysPage( nLast << 2 );
+ if( !pPg )
+ return STG_EOF;
+ pPg->SetPage( nOffset >> 2, nBegin );
+ }
+ nLast = nBegin + nAlloc - 1;
+ nPgs -= nAlloc;
+ }
+ if( nPgs && !nPasses )
+ {
+ // we need new, fresh space, so allocate and retry
+ if( !rStrm.SetSize( ( nPages + nPgs ) << 2 ) )
+ return STG_EOF;
+ if( !bPhys && !InitNew( nPages ) )
+ return FALSE;
+ nPages = rStrm.GetSize() >> 2;
+ nPasses++;
+ }
+ else
+ break;
+ }
+ // now we should have a chain for the complete block
+ if( nBegin == STG_EOF || nPgs )
+ {
+ rStrm.GetIo().SetError( SVSTREAM_FILEFORMAT_ERROR );
+ return STG_EOF; // bad structure
+ }
+ return nOrig;
+}
+
+// Initialize newly allocated pages for a standard FAT stream
+// It can be assumed that the stream size is always on
+// a page boundary
+
+BOOL StgFAT::InitNew( INT32 nPage1 )
+{
+ INT32 n = ( ( rStrm.GetSize() >> 2 ) - nPage1 ) / nEntries;
+ while( n-- )
+ {
+ StgPage* pPg = NULL;
+ // Position within the underlying stream
+ // use the Pos2Page() method of the stream
+ rStrm.Pos2Page( nPage1 << 2 );
+ // Initialize the page
+ pPg = rStrm.GetIo().Copy( rStrm.GetPage(), STG_FREE );
+ for( short i = 0; i < nEntries; i++ )
+ pPg->SetPage( i, STG_FREE );
+ nPage1++;
+ }
+ return TRUE;
+}
+
+// Release a chain
+
+BOOL StgFAT::FreePages( INT32 nStart, BOOL bAll )
+{
+ while( nStart >= 0 )
+ {
+ StgPage* pPg = GetPhysPage( nStart << 2 );
+ if( !pPg )
+ return FALSE;
+ nStart = pPg->GetPage( nOffset >> 2 );
+ // The first released page is either set to EOF or FREE
+ pPg->SetPage( nOffset >> 2, bAll ? STG_FREE : STG_EOF );
+ bAll = TRUE;
+ }
+ return TRUE;
+}
+
+///////////////////////////// class StgStrm ////////////////////////////////
+
+// The base stream class provides basic functionality for seeking
+// and accessing the data on a physical basis. It uses the built-in
+// FAT class for the page allocations.
+
+StgStrm::StgStrm( StgIo& r ) : rIo( r )
+{
+ pFat = NULL;
+ nStart = nPage = STG_EOF;
+ nOffset = 0;
+ pEntry = NULL;
+ nPos = nSize = 0;
+ nPageSize = rIo.GetPhysPageSize();
+}
+
+StgStrm::~StgStrm()
+{
+ delete pFat;
+}
+
+// Attach the stream to the given entry.
+
+void StgStrm::SetEntry( StgDirEntry& r )
+{
+ r.aEntry.SetLeaf( STG_DATA, nStart );
+ r.aEntry.SetSize( nSize );
+ pEntry = &r;
+ r.SetDirty();
+}
+
+// Compute page number and offset for the given byte position.
+// If the position is behind the size, set the stream right
+// behind the EOF.
+
+BOOL StgStrm::Pos2Page( INT32 nBytePos )
+{
+ INT32 nRel, nBgn;
+ // Values < 0 seek to the end
+ if( nBytePos < 0 || nBytePos >= nSize )
+ nBytePos = nSize;
+ // Adjust the position back to offset 0
+ nPos -= nOffset;
+ INT32 nMask = ~( nPageSize - 1 );
+ INT32 nOld = nPos & nMask;
+ INT32 nNew = nBytePos & nMask;
+ nOffset = (short) ( nBytePos & ~nMask );
+ nPos = nBytePos;
+ if( nOld == nNew )
+ return TRUE;
+ if( nNew > nOld )
+ {
+ // the new position is behind the current, so an incremental
+ // positioning is OK. Set the page relative position
+ nRel = nNew - nOld;
+ nBgn = nPage;
+ }
+ else
+ {
+ // the new position is before the current, so we have to scan
+ // the entire chain.
+ nRel = nNew;
+ nBgn = nStart;
+ }
+ // now, traverse the FAT chain.
+ nRel /= nPageSize;
+ INT32 nLast = STG_EOF;
+ while( nRel && nBgn >= 0 )
+ {
+ nLast = nBgn;
+ nBgn = pFat->GetNextPage( nBgn );
+ nRel--;
+ }
+ // special case: seek to 1st byte of new, unallocated page
+ // (in case the file size is a multiple of the page size)
+ if( nBytePos == nSize && nBgn == STG_EOF && !nRel && !nOffset )
+ nBgn = nLast, nOffset = nPageSize;
+ if( nBgn < 0 && nBgn != STG_EOF )
+ {
+ rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
+ nBgn = STG_EOF;
+ nOffset = nPageSize;
+ }
+ nPage = nBgn;
+ return BOOL( nRel == 0 && nPage >= 0 );
+}
+
+// Retrieve the physical page for a given byte offset.
+
+StgPage* StgStrm::GetPhysPage( INT32 nBytePos, BOOL bForce )
+{
+ if( !Pos2Page( nBytePos ) )
+ return NULL;
+ return rIo.Get( nPage, bForce );
+}
+
+// Copy an entire stream. Both streams are allocated in the FAT.
+// The target stream is this stream.
+
+BOOL StgStrm::Copy( INT32 nFrom, INT32 nBytes )
+{
+ INT32 nTo = nStart;
+ INT32 nPgs = ( nBytes + nPageSize - 1 ) / nPageSize;
+ while( nPgs-- )
+ {
+ if( nTo < 0 )
+ {
+ rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
+ return FALSE;
+ }
+ rIo.Copy( nTo, nFrom );
+ if( nFrom >= 0 )
+ {
+ nFrom = pFat->GetNextPage( nFrom );
+ if( nFrom < 0 )
+ {
+ rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
+ return FALSE;
+ }
+ }
+ nTo = pFat->GetNextPage( nTo );
+ }
+ return TRUE;
+}
+
+BOOL StgStrm::SetSize( INT32 nBytes )
+{
+ // round up to page size
+ INT32 nOld = ( ( nSize + nPageSize - 1 ) / nPageSize ) * nPageSize;
+ INT32 nNew = ( ( nBytes + nPageSize - 1 ) / nPageSize ) * nPageSize;
+ if( nNew > nOld )
+ {
+ if( !Pos2Page( nSize ) )
+ return FALSE;
+ INT32 nBgn = pFat->AllocPages( nPage, ( nNew - nOld ) / nPageSize );
+ if( nBgn == STG_EOF )
+ return FALSE;
+ if( nStart == STG_EOF )
+ nStart = nPage = nBgn;
+ }
+ else if( nNew < nOld )
+ {
+ BOOL bAll = BOOL( nBytes == 0 );
+ if( !Pos2Page( nBytes ) || !pFat->FreePages( nPage, bAll ) )
+ return FALSE;
+ if( bAll )
+ nStart = nPage = STG_EOF;
+ }
+ if( pEntry )
+ {
+ // change the dir entry?
+ if( !nSize || !nBytes )
+ pEntry->aEntry.SetLeaf( STG_DATA, nStart );
+ pEntry->aEntry.SetSize( nBytes );
+ pEntry->SetDirty();
+ }
+ nSize = nBytes;
+ pFat->SetLimit( GetPages() );
+ return TRUE;
+}
+
+// Return the # of allocated pages
+
+INT32 StgStrm::GetPages()
+{
+ return ( nSize + nPageSize - 1 ) / nPageSize;
+}
+
+//////////////////////////// class StgFATStrm //////////////////////////////
+
+// The FAT stream class provides physical access to the master FAT.
+// Since this access is implemented as a StgStrm, we can use the
+// FAT allocator.
+
+StgFATStrm::StgFATStrm( StgIo& r ) : StgStrm( r )
+{
+ pFat = new StgFAT( *this, TRUE );
+ nSize = rIo.aHdr.GetFATSize() * nPageSize;
+}
+
+BOOL StgFATStrm::Pos2Page( INT32 nBytePos )
+{
+ // Values < 0 seek to the end
+ if( nBytePos < 0 || nBytePos >= nSize )
+ nBytePos = nSize ? nSize - 1 : 0;
+ nPage = nBytePos / nPageSize;
+ nOffset = (short) ( nBytePos % nPageSize );
+ nPos = nBytePos;
+ nPage = GetPage( (short) nPage, FALSE );
+ return BOOL( nPage >= 0 );
+}
+
+// Retrieve the physical page for a given byte offset.
+// Since Pos2Page() already has computed the physical offset,
+// use the byte offset directly.
+
+StgPage* StgFATStrm::GetPhysPage( INT32 nBytePos, BOOL bForce )
+{
+ return rIo.Get( nBytePos / ( nPageSize >> 2 ), bForce );
+}
+
+// Get the page number entry for the given page offset.
+
+INT32 StgFATStrm::GetPage( short nOff, BOOL bMake, USHORT *pnMasterAlloc )
+{
+ if( pnMasterAlloc ) *pnMasterAlloc = 0;
+ if( nOff < rIo.aHdr.GetFAT1Size() )
+ return rIo.aHdr.GetFATPage( nOff );
+ INT32 nMaxPage = nSize >> 2;
+ nOff -= rIo.aHdr.GetFAT1Size();
+ // Anzahl der Masterpages, durch die wir iterieren muessen
+ USHORT nMasterCount = ( nPageSize >> 2 ) - 1;
+ USHORT nBlocks = nOff / nMasterCount;
+ // Offset in letzter Masterpage
+ nOff = nOff % nMasterCount;
+
+ StgPage* pOldPage = 0;
+ StgPage* pMaster = 0;
+ INT32 nFAT = rIo.aHdr.GetFATChain();
+ for( USHORT nCount = 0; nCount <= nBlocks; nCount++ )
+ {
+ if( nFAT == STG_EOF || nFAT == STG_FREE )
+ {
+ if( bMake )
+ {
+ // create a new master page
+ nFAT = nMaxPage++;
+ pMaster = rIo.Copy( nFAT, STG_FREE );
+ for( short k = 0; k < ( nPageSize >> 2 ); k++ )
+ pMaster->SetPage( k, STG_FREE );
+ // Verkettung herstellen
+ if( !pOldPage )
+ rIo.aHdr.SetFATChain( nFAT );
+ else
+ pOldPage->SetPage( nMasterCount, nFAT );
+ if( nMaxPage >= rIo.GetPhysPages() )
+ if( !rIo.SetSize( nMaxPage ) )
+ return STG_EOF;
+ // mark the page as used
+ // Platz fuer Masterpage schaffen
+ if( !pnMasterAlloc ) // Selbst Platz schaffen
+ {
+ if( !Pos2Page( nFAT << 2 ) )
+ return STG_EOF;
+ StgPage* pPg = rIo.Get( nPage, TRUE );
+ if( !pPg )
+ return STG_EOF;
+ pPg->SetPage( nOffset >> 2, STG_MASTER );
+ }
+ else
+ (*pnMasterAlloc)++;
+ rIo.aHdr.SetMasters( nCount + 1 );
+ pOldPage = pMaster;
+ }
+ }
+ else
+ {
+ pMaster = rIo.Get( nFAT, TRUE );
+ nFAT = pMaster->GetPage( nMasterCount );
+ pOldPage = pMaster;
+ }
+ }
+ if( pMaster )
+ return pMaster->GetPage( nOff );
+ rIo.SetError( SVSTREAM_GENERALERROR );
+ return STG_EOF;
+}
+
+
+// Set the page number entry for the given page offset.
+
+BOOL StgFATStrm::SetPage( short nOff, INT32 nNewPage )
+{
+ BOOL bRes = TRUE;
+ if( nOff < rIo.aHdr.GetFAT1Size() )
+ rIo.aHdr.SetFATPage( nOff, nNewPage );
+ else
+ {
+ nOff -= rIo.aHdr.GetFAT1Size();
+ // Anzahl der Masterpages, durch die wir iterieren muessen
+ USHORT nMasterCount = ( nPageSize >> 2 ) - 1;
+ USHORT nBlocks = nOff / nMasterCount;
+ // Offset in letzter Masterpage
+ nOff = nOff % nMasterCount;
+
+ StgPage* pMaster = 0;
+ INT32 nFAT = rIo.aHdr.GetFATChain();
+ for( USHORT nCount = 0; nCount <= nBlocks; nCount++ )
+ {
+ if( nFAT == STG_EOF || nFAT == STG_FREE )
+ {
+ pMaster = 0;
+ break;
+ }
+ pMaster = rIo.Get( nFAT, TRUE );
+ nFAT = pMaster->GetPage( nMasterCount );
+ }
+ if( pMaster )
+ pMaster->SetPage( nOff, nNewPage );
+ else
+ {
+ rIo.SetError( SVSTREAM_GENERALERROR );
+ bRes = FALSE;
+ }
+ }
+
+ // lock the page against access
+ if( bRes )
+ {
+ Pos2Page( nNewPage << 2 );
+ StgPage* pPg = rIo.Get( nPage, TRUE );
+ if( pPg )
+ pPg->SetPage( nOffset >> 2, STG_FAT );
+ else
+ bRes = FALSE;
+ }
+ return bRes;
+}
+
+BOOL StgFATStrm::SetSize( INT32 nBytes )
+{
+ // Set the number of entries to a multiple of the page size
+ short nOld = (short) ( ( nSize + ( nPageSize - 1 ) ) / nPageSize );
+ short nNew = (short) (
+ ( nBytes + ( nPageSize - 1 ) ) / nPageSize ) ;
+ if( nNew < nOld )
+ {
+ // release master pages
+ for( short i = nNew; i < nOld; i++ )
+ SetPage( i, STG_FREE );
+ }
+ else
+ {
+ while( nOld < nNew )
+ {
+ // allocate master pages
+ // find a free master page slot
+ INT32 nPg = 0;
+ USHORT nMasterAlloc = 0;
+ nPg = GetPage( nOld, TRUE, &nMasterAlloc );
+ if( nPg == STG_EOF )
+ return FALSE;
+ // 4 Bytes have been used for Allocation of each MegaMasterPage
+ nBytes += nMasterAlloc << 2;
+
+ // find a free page using the FAT allocator
+ INT32 n = 1;
+ INT32 nNewPage = pFat->FindBlock( n );
+ if( nNewPage == STG_EOF )
+ {
+ // no free pages found; create a new page
+ // Since all pages are allocated, extend
+ // the file size for the next page!
+ nNewPage = nSize >> 2;
+ // if a MegaMasterPage was created avoid taking
+ // the same Page
+ nNewPage += nMasterAlloc;
+ // adjust the file size if necessary
+ if( nNewPage >= rIo.GetPhysPages() )
+ if( !rIo.SetSize( nNewPage + 1 ) )
+ return FALSE;
+ }
+ // Set up the page with empty entries
+ StgPage* pPg = rIo.Copy( nNewPage, STG_FREE );
+ for( short j = 0; j < ( nPageSize >> 2 ); j++ )
+ pPg->SetPage( j, STG_FREE );
+
+ // store the page number into the master FAT
+ // Set the size before so the correct FAT can be found
+ nSize = ( nOld + 1 ) * nPageSize;
+ SetPage( nOld, nNewPage );
+
+ // MegaMasterPages were created, mark it them as used
+
+ UINT32 nMax = rIo.aHdr.GetMasters( );
+ UINT32 nFAT = rIo.aHdr.GetFATChain();
+ if( nMasterAlloc )
+ for( USHORT nCount = 0; nCount < nMax; nCount++ )
+ {
+ if( !Pos2Page( nFAT << 2 ) )
+ return FALSE;
+ if( nMax - nCount <= nMasterAlloc )
+ {
+ StgPage* pPg = rIo.Get( nPage, TRUE );
+ if( !pPg )
+ return FALSE;
+ pPg->SetPage( nOffset >> 2, STG_MASTER );
+ }
+ StgPage* pPage = rIo.Get( nFAT, TRUE );
+ if( !pPage ) return FALSE;
+ nFAT = pPage->GetPage( (nPageSize >> 2 ) - 1 );
+ }
+
+ nOld++;
+ // We have used up 4 bytes for the STG_FAT entry
+ nBytes += 4;
+ nNew = (short) (
+ ( nBytes + ( nPageSize - 1 ) ) / nPageSize );
+ }
+ }
+ nSize = nNew * nPageSize;
+ rIo.aHdr.SetFATSize( nNew );
+ return TRUE;
+}
+
+/////////////////////////// class StgDataStrm //////////////////////////////
+
+// This class is a normal physical stream which can be initialized
+// either with an existing dir entry or an existing FAT chain.
+// The stream has a size increment which normally is 1, but which can be
+// set to any value is you want the size to be incremented by certain values.
+
+StgDataStrm::StgDataStrm( StgIo& r, INT32 nBgn, INT32 nLen ) : StgStrm( r )
+{
+ Init( nBgn, nLen );
+}
+
+StgDataStrm::StgDataStrm( StgIo& r, StgDirEntry* p ) : StgStrm( r )
+{
+ pEntry = p;
+ Init( p->aEntry.GetLeaf( STG_DATA ),
+ p->aEntry.GetSize() );
+}
+
+void StgDataStrm::Init( INT32 nBgn, INT32 nLen )
+{
+ pFat = new StgFAT( *rIo.pFAT, TRUE );
+ nStart = nPage = nBgn;
+ nSize = nLen;
+ nIncr = 1;
+ nOffset = 0;
+ if( nLen < 0 )
+ {
+ // determine the actual size of the stream by scanning
+ // the FAT chain and counting the # of pages allocated
+ nSize = 0;
+ INT32 nOldBgn = -1;
+ while( nBgn >= 0 && nBgn != nOldBgn )
+ {
+ nOldBgn = nBgn;
+ nBgn = pFat->GetNextPage( nBgn );
+ if( nBgn == nOldBgn )
+ rIo.SetError( ERRCODE_IO_WRONGFORMAT );
+ nSize += nPageSize;
+ }
+ }
+}
+
+// Set the size of a physical stream.
+
+BOOL StgDataStrm::SetSize( INT32 nBytes )
+{
+ nBytes = ( ( nBytes + nIncr - 1 ) / nIncr ) * nIncr;
+ INT32 nOldSz = nSize;
+ if( ( nOldSz != nBytes ) )
+ {
+ if( !StgStrm::SetSize( nBytes ) )
+ return FALSE;
+ INT32 nMaxPage = pFat->GetMaxPage();
+ if( nMaxPage > rIo.GetPhysPages() )
+ if( !rIo.SetSize( nMaxPage ) )
+ return FALSE;
+ // If we only allocated one page or less, create this
+ // page in the cache for faster throughput. The current
+ // position is the former EOF point.
+ if( ( nSize - 1 ) / nPageSize - ( nOldSz - 1 ) / nPageSize == 1 )
+ {
+ Pos2Page( nBytes );
+ if( nPage >= 0 )
+ rIo.Copy( nPage, STG_FREE );
+ }
+ }
+ return TRUE;
+}
+
+// Get the address of the data byte at a specified offset.
+// If bForce = TRUE, a read of non-existent data causes
+// a read fault.
+
+void* StgDataStrm::GetPtr( INT32 nPos, BOOL bForce, BOOL bDirty )
+{
+ if( Pos2Page( nPos ) )
+ {
+ StgPage* pPg = rIo.Get( nPage, bForce );
+ if( pPg )
+ {
+ pPg->SetOwner( pEntry );
+ if( bDirty )
+ pPg->SetDirty();
+ return ((BYTE *)pPg->GetData()) + nOffset;
+ }
+ }
+ return NULL;
+}
+
+// This could easily be adapted to a better algorithm by determining
+// the amount of consecutable blocks before doing a read. The result
+// is the number of bytes read. No error is generated on EOF.
+
+INT32 StgDataStrm::Read( void* pBuf, INT32 n )
+{
+ if( ( nPos + n ) > nSize )
+ n = nSize - nPos;
+ INT32 nDone = 0;
+ while( n )
+ {
+ short nBytes = nPageSize - nOffset;
+ short nRes;
+ StgPage* pPg;
+ if( (INT32) nBytes > n )
+ nBytes = (short) n;
+ if( nBytes )
+ {
+ void *p = (BYTE *) pBuf + nDone;
+ if( nBytes == nPageSize )
+ {
+ pPg = rIo.Find( nPage );
+ if( pPg )
+ {
+ // data is present, so use the cached data
+ pPg->SetOwner( pEntry );
+ memcpy( p, pPg->GetData(), nBytes );
+ nRes = nBytes;
+ }
+ else
+ // do a direct (unbuffered) read
+ nRes = (short) rIo.Read( nPage, p, 1 ) * nPageSize;
+ }
+ else
+ {
+ // partial block read thru the cache.
+ pPg = rIo.Get( nPage, FALSE );
+ if( !pPg )
+ break;
+ pPg->SetOwner( pEntry );
+ memcpy( p, (BYTE*)pPg->GetData() + nOffset, nBytes );
+ nRes = nBytes;
+ }
+ nDone += nRes;
+ nPos += nRes;
+ n -= nRes;
+ nOffset += nRes;
+ if( nRes != nBytes )
+ break; // read error or EOF
+ }
+ // Switch to next page if necessary
+ if( nOffset >= nPageSize && !Pos2Page( nPos ) )
+ break;
+ }
+ return nDone;
+}
+
+INT32 StgDataStrm::Write( const void* pBuf, INT32 n )
+{
+ INT32 nDone = 0;
+ if( ( nPos + n ) > nSize )
+ {
+ INT32 nOld = nPos;
+ if( !SetSize( nPos + n ) )
+ return FALSE;
+ Pos2Page( nOld );
+ }
+ while( n )
+ {
+ short nBytes = nPageSize - nOffset;
+ short nRes;
+ StgPage* pPg;
+ if( (INT32) nBytes > n )
+ nBytes = (short) n;
+ if( nBytes )
+ {
+ const void *p = (const BYTE *) pBuf + nDone;
+ if( nBytes == nPageSize )
+ {
+ pPg = rIo.Find( nPage );
+ if( pPg )
+ {
+ // data is present, so use the cached data
+ pPg->SetOwner( pEntry );
+ memcpy( pPg->GetData(), p, nBytes );
+ pPg->SetDirty();
+ nRes = nBytes;
+ }
+ else
+ // do a direct (unbuffered) write
+ nRes = (short) rIo.Write( nPage, (void*) p, 1 ) * nPageSize;
+ }
+ else
+ {
+ // partial block read thru the cache.
+ pPg = rIo.Get( nPage, FALSE );
+ if( !pPg )
+ break;
+ pPg->SetOwner( pEntry );
+ memcpy( (BYTE*)pPg->GetData() + nOffset, p, nBytes );
+ pPg->SetDirty();
+ nRes = nBytes;
+ }
+ nDone += nRes;
+ nPos += nRes;
+ n -= nRes;
+ nOffset += nRes;
+ if( nRes != nBytes )
+ break; // read error
+ }
+ // Switch to next page if necessary
+ if( nOffset >= nPageSize && !Pos2Page( nPos ) )
+ break;
+ }
+ return nDone;
+}
+
+//////////////////////////// class StgSmallStream ///////////////////////////
+
+// The small stream class provides access to streams with a size < 4096 bytes.
+// This stream is a StgStream containing small pages. The FAT for this stream
+// is also a StgStream. The start of the FAT is in the header at DataRootPage,
+// the stream itself is pointed to by the root entry (it holds start & size).
+
+StgSmallStrm::StgSmallStrm( StgIo& r, INT32 nBgn, INT32 nLen ) : StgStrm( r )
+{
+ Init( nBgn, nLen );
+}
+
+StgSmallStrm::StgSmallStrm( StgIo& r, StgDirEntry* p ) : StgStrm( r )
+{
+ pEntry = p;
+ Init( p->aEntry.GetLeaf( STG_DATA ),
+ p->aEntry.GetSize() );
+}
+
+void StgSmallStrm::Init( INT32 nBgn, INT32 nLen )
+{
+ pFat = new StgFAT( *rIo.pDataFAT, FALSE );
+ pData = rIo.pDataStrm;
+ nPageSize = rIo.GetDataPageSize();
+ nStart =
+ nPage = nBgn;
+ nSize = nLen;
+}
+
+// This could easily be adapted to a better algorithm by determining
+// the amount of consecutable blocks before doing a read. The result
+// is the number of bytes read. No error is generated on EOF.
+
+INT32 StgSmallStrm::Read( void* pBuf, INT32 n )
+{
+ // We can safely assume that reads are not huge, since the
+ // small stream is likely to be < 64 KBytes.
+ if( ( nPos + n ) > nSize )
+ n = nSize - nPos;
+ short nDone = 0;
+ while( n )
+ {
+ short nBytes = nPageSize - nOffset;
+ if( (INT32) nBytes > n )
+ nBytes = (short) n;
+ if( nBytes )
+ {
+ if( !pData->Pos2Page( nPage * nPageSize + nOffset ) )
+ break;
+ // all reading thru the stream
+ short nRes = (short) pData->Read( (BYTE*)pBuf + nDone, nBytes );
+ nDone += nRes;
+ nPos += nRes;
+ n -= nRes;
+ nOffset += nRes;
+ // read problem?
+ if( nRes != nBytes )
+ break;
+ }
+ // Switch to next page if necessary
+ if( nOffset >= nPageSize && !Pos2Page( nPos ) )
+ break;
+ }
+ return nDone;
+}
+
+INT32 StgSmallStrm::Write( const void* pBuf, INT32 n )
+{
+ // you can safely assume that reads are not huge, since the
+ // small stream is likely to be < 64 KBytes.
+ short nDone = 0;
+ if( ( nPos + n ) > nSize )
+ {
+ INT32 nOld = nPos;
+ if( !SetSize( nPos + n ) )
+ return FALSE;
+ Pos2Page( nOld );
+ }
+ while( n )
+ {
+ short nBytes = nPageSize - nOffset;
+ if( (INT32) nBytes > n )
+ nBytes = (short) n;
+ if( nBytes )
+ {
+ // all writing goes thru the stream
+ INT32 nDataPos = nPage * nPageSize + nOffset;
+ if( pData->GetSize() < ( nDataPos + nBytes ) )
+ if( !pData->SetSize( nDataPos + nBytes ) )
+ break;
+ if( !pData->Pos2Page( nDataPos ) )
+ break;
+ short nRes = (short) pData->Write( (BYTE*)pBuf + nDone, nBytes );
+ nDone += nRes;
+ nPos += nRes;
+ n -= nRes;
+ nOffset += nRes;
+ // write problem?
+ if( nRes != nBytes )
+ break;
+ }
+ // Switch to next page if necessary
+ if( nOffset >= nPageSize && !Pos2Page( nPos ) )
+ break;
+ }
+ return nDone;
+}
+
+/////////////////////////// class StgTmpStrm /////////////////////////////
+
+// The temporary stream uses a memory stream if < 32K, otherwise a
+// temporary file.
+
+#define THRESHOLD 32768L
+
+StgTmpStrm::StgTmpStrm( ULONG nInitSize )
+ : SvMemoryStream( nInitSize > THRESHOLD
+ ? 16
+ : ( nInitSize ? nInitSize : 16 ), 4096 )
+{
+ pStrm = NULL;
+ // this calls FlushData, so all members should be set by this time
+ SetBufferSize( 0 );
+ if( nInitSize > THRESHOLD )
+ SetSize( nInitSize );
+}
+
+BOOL StgTmpStrm::Copy( StgTmpStrm& rSrc )
+{
+ ULONG n = rSrc.GetSize();
+ ULONG nCur = rSrc.Tell();
+ SetSize( n );
+ if( GetError() == SVSTREAM_OK )
+ {
+ void* p = new BYTE[ 4096 ];
+ rSrc.Seek( 0L );
+ Seek( 0L );
+ while( n )
+ {
+ ULONG nn = n;
+ if( nn > 4096 )
+ nn = 4096;
+ if( rSrc.Read( p, nn ) != nn )
+ break;
+ if( Write( p, nn ) != nn )
+ break;
+ n -= nn;
+ }
+ delete p;
+ rSrc.Seek( nCur );
+ Seek( nCur );
+ return BOOL( n == 0 );
+ }
+ else
+ return FALSE;
+}
+
+StgTmpStrm::~StgTmpStrm()
+{
+ if( pStrm )
+ {
+ pStrm->Close();
+ DirEntry aEntry( aName );
+ aEntry.Kill();
+ delete pStrm;
+ }
+}
+
+ULONG StgTmpStrm::GetSize()
+{
+ ULONG n;
+ if( pStrm )
+ {
+ ULONG old = pStrm->Tell();
+ n = pStrm->Seek( STREAM_SEEK_TO_END );
+ pStrm->Seek( old );
+ }
+ else
+ n = nEndOfData;
+ return n;
+}
+
+void StgTmpStrm::SetSize( ULONG n )
+{
+ if( pStrm )
+ pStrm->SetStreamSize( n );
+ else
+ {
+ if( n > THRESHOLD )
+ {
+ DirEntry aEntry;
+ aEntry = aEntry.TempName();
+ aName = aEntry.GetFull();
+ SvFileStream* s = new SvFileStream( aName, STREAM_READWRITE );
+ ULONG nCur = Tell();
+ ULONG i = nEndOfData;
+ if( i )
+ {
+ void* p = new BYTE[ 4096 ];
+ Seek( 0L );
+ while( i )
+ {
+ ULONG nb = ( i > 4096 ) ? 4096 : i;
+ if( Read( p, nb ) == nb
+ && s->Write( p, nb ) == nb )
+ i -= nb;
+ else
+ break;
+ }
+ delete p;
+ }
+ if( !i && n > nEndOfData )
+ {
+ // We have to write one byte at the end of the file
+ // if the file is bigger than the memstream to see
+ // if it fits on disk
+ s->Seek( n - 1 );
+ s->Write( &i, 1 );
+ s->Flush();
+ if( s->GetError() != SVSTREAM_OK )
+ i = 1;
+ }
+ Seek( nCur );
+ s->Seek( nCur );
+ if( i )
+ {
+ SetError( s->GetError() );
+ delete s;
+ return;
+ }
+ pStrm = s;
+ // Shrink the memory to 16 bytes, which seems to be the minimum
+ ReAllocateMemory( - ( (long) nEndOfData - 16 ) );
+ }
+ else
+ {
+ if( n > nEndOfData )
+ {
+ ULONG nCur = Tell();
+ Seek( nEndOfData - 1 );
+ *this << (BYTE) 0;
+ Seek( nCur );
+ }
+ else
+ nEndOfData = n;
+ }
+ }
+}
+
+ULONG StgTmpStrm::GetData( void* pData, ULONG n )
+{
+ if( pStrm )
+ {
+ n = pStrm->Read( pData, n );
+ SetError( pStrm->GetError() );
+ return n;
+ }
+ else
+ return SvMemoryStream::GetData( (sal_Char *)pData, n );
+}
+
+ULONG StgTmpStrm::PutData( const void* pData, ULONG n )
+{
+ UINT32 nCur = Tell();
+ UINT32 nNew = nCur + n;
+ if( nNew > THRESHOLD && !pStrm )
+ {
+ SetSize( nNew );
+ if( GetError() != SVSTREAM_OK )
+ return 0;
+ }
+ if( pStrm )
+ {
+ nNew = pStrm->Write( pData, n );
+ SetError( pStrm->GetError() );
+ }
+ else
+ nNew = SvMemoryStream::PutData( (sal_Char*)pData, n );
+ return nNew;
+}
+
+ULONG StgTmpStrm::SeekPos( ULONG n )
+{
+ if( n == STREAM_SEEK_TO_END )
+ n = GetSize();
+ if( n && n > THRESHOLD && !pStrm )
+ {
+ SetSize( n );
+ if( GetError() != SVSTREAM_OK )
+ return Tell();
+ else
+ return n;
+ }
+ else if( pStrm )
+ {
+ n = pStrm->Seek( n );
+ SetError( pStrm->GetError() );
+ return n;
+ }
+ else
+ return SvMemoryStream::SeekPos( n );
+}
+
+void StgTmpStrm::FlushData()
+{
+ if( pStrm )
+ {
+ pStrm->Flush();
+ SetError( pStrm->GetError() );
+ }
+ else
+ SvMemoryStream::FlushData();
+}
+
diff --git a/sot/source/sdstor/stgstrms.hxx b/sot/source/sdstor/stgstrms.hxx
new file mode 100644
index 000000000000..a63d664d6967
--- /dev/null
+++ b/sot/source/sdstor/stgstrms.hxx
@@ -0,0 +1,201 @@
+/*************************************************************************
+ *
+ * $RCSfile: stgstrms.hxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:52 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifndef _STGSTRMS_HXX
+#define _STGSTRMS_HXX
+
+#ifndef _TOOLS_STREAM_HXX
+#include <tools/stream.hxx>
+#endif
+
+class StgIo;
+class StgStrm;
+class StgPage;
+class StgDirEntry;
+
+// The FAT class performs FAT operations on an underlying storage stream.
+// This stream is either the physical FAT stream (bPhys == TRUE ) or a normal
+// storage stream, which then holds the FAT for small data allocations.
+
+class StgFAT
+{ // FAT allocator
+ StgStrm& rStrm; // underlying stream
+ INT32 nMaxPage; // highest page allocated so far
+ short nPageSize; // physical page size
+ short nEntries; // FAT entries per page
+ short nOffset; // current offset within page
+ INT32 nLimit; // search limit recommendation
+ BOOL bPhys; // TRUE: physical FAT
+ StgPage* GetPhysPage( INT32 nPage );
+ BOOL MakeChain( INT32 nStart, INT32 nPages );
+ BOOL InitNew( INT32 nPage1 );
+public:
+ StgFAT( StgStrm& rStrm, BOOL bMark );
+ INT32 FindBlock( INT32& nPages );
+ INT32 GetNextPage( INT32 nPg );
+ INT32 AllocPages( INT32 nStart, INT32 nPages );
+ BOOL FreePages( INT32 nStart, BOOL bAll );
+ INT32 GetMaxPage() { return nMaxPage; }
+ void SetLimit( INT32 n ) { nLimit = n; }
+};
+
+// The base stream class provides basic functionality for seeking
+// and accessing the data on a physical basis. It uses the built-in
+// FAT class for the page allocations.
+
+class StgStrm { // base class for all streams
+protected:
+ StgIo& rIo; // I/O system
+ StgFAT* pFat; // FAT stream for allocations
+ StgDirEntry* pEntry; // dir entry (for ownership)
+ INT32 nStart; // 1st data page
+ INT32 nSize; // stream size in bytes
+ INT32 nPos; // current byte position
+ INT32 nPage; // current logical page
+ short nOffset; // offset into current page
+ short nPageSize; // logical page size
+ BOOL Copy( INT32 nFrom, INT32 nBytes );
+ StgStrm( StgIo& );
+public:
+ ~StgStrm();
+ StgIo& GetIo() { return rIo; }
+ INT32 GetPos() { return nPos; }
+ INT32 GetStart() { return nStart; }
+ INT32 GetSize() { return nSize; }
+ INT32 GetPage() { return nPage; }
+ short GetPageSize() { return nPageSize; }
+ INT32 GetPages();
+ short GetOffset() { return nOffset;}
+ void SetEntry( StgDirEntry& );
+ virtual BOOL SetSize( INT32 );
+ virtual BOOL Pos2Page( INT32 nBytePos );
+ virtual INT32 Read( void*, INT32 ) { return 0; }
+ virtual INT32 Write( const void*, INT32 ) { return 0; }
+ virtual StgPage* GetPhysPage( INT32 nBytePos, BOOL bForce = FALSE );
+ virtual BOOL IsSmallStrm() { return FALSE; }
+};
+
+// The FAT stream class provides physical access to the master FAT.
+// Since this access is implemented as a StgStrm, we can use the
+// FAT allocator.
+
+class StgFATStrm : public StgStrm { // the master FAT stream
+ virtual BOOL Pos2Page( INT32 nBytePos );
+ BOOL SetPage( short, INT32 );
+public:
+ StgFATStrm( StgIo& );
+ INT32 GetPage( short, BOOL, USHORT *pnMasterAlloc = 0);
+ virtual BOOL SetSize( INT32 );
+ virtual StgPage* GetPhysPage( INT32 nBytePos, BOOL bForce = FALSE );
+};
+
+// The stream has a size increment which normally is 1, but which can be
+// set to any value is you want the size to be incremented by certain values.
+
+class StgDataStrm : public StgStrm // a physical data stream
+{
+ short nIncr; // size adjust increment
+ void Init( INT32 nBgn, INT32 nLen );
+public:
+ StgDataStrm( StgIo&, INT32 nBgn, INT32 nLen=-1 );
+ StgDataStrm( StgIo&, StgDirEntry* );
+ void* GetPtr( INT32 nPos, BOOL bForce, BOOL bDirty );
+ void SetIncrement( short n ) { nIncr = n ; }
+ virtual BOOL SetSize( INT32 );
+ virtual INT32 Read( void*, INT32 );
+ virtual INT32 Write( const void*, INT32 );
+};
+
+// The small stream class provides access to streams with a size < 4096 bytes.
+// This stream is a StgStream containing small pages. The FAT for this stream
+// is also a StgStream. The start of the FAT is in the header at DataRootPage,
+// the stream itself is pointed to by the root entry (it holds start & size).
+
+class StgSmallStrm : public StgStrm // a logical data stream
+{
+ StgStrm* pData; // the data stream
+ void Init( INT32 nBgn, INT32 nLen );
+public:
+ StgSmallStrm( StgIo&, INT32 nBgn, INT32 nLen );
+ StgSmallStrm( StgIo&, StgDirEntry* );
+ virtual INT32 Read( void*, INT32 );
+ virtual INT32 Write( const void*, INT32 );
+ virtual BOOL IsSmallStrm() { return TRUE; }
+};
+
+class StgTmpStrm : public SvMemoryStream
+{
+ String aName;
+ SvFileStream* pStrm;
+ virtual ULONG GetData( void* pData, ULONG nSize );
+ virtual ULONG PutData( const void* pData, ULONG nSize );
+ virtual ULONG SeekPos( ULONG nPos );
+ virtual void FlushData();
+
+public:
+ StgTmpStrm( ULONG=16 );
+ ~StgTmpStrm();
+ BOOL Copy( StgTmpStrm& );
+ void SetSize( ULONG );
+ ULONG GetSize();
+};
+
+#endif
diff --git a/sot/source/sdstor/storage.cxx b/sot/source/sdstor/storage.cxx
new file mode 100644
index 000000000000..c47f107b30ca
--- /dev/null
+++ b/sot/source/sdstor/storage.cxx
@@ -0,0 +1,948 @@
+/*************************************************************************
+ *
+ * $RCSfile: storage.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:52 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <stg.hxx>
+#include <storinfo.hxx>
+#include <storage.hxx>
+
+#ifndef _TOOLS_FSYS_HXX
+#include <tools/fsys.hxx>
+#endif
+#ifndef _CACHESTR_HXX //autogen
+#include <tools/cachestr.hxx>
+#endif
+#include <tools/debug.hxx>
+#pragma hdrstop
+
+/************** class SotStorageStream ***********************************/
+class SotStorageStreamFactory : public SotFactory
+{
+public:
+ TYPEINFO();
+ SotStorageStreamFactory( const SvGlobalName & rName,
+ const String & rClassName,
+ CreateInstanceType pCreateFuncP )
+ : SotFactory( rName, rClassName, pCreateFuncP )
+ {}
+};
+TYPEINIT1(SotStorageStreamFactory,SotFactory);
+
+
+SO2_IMPL_BASIC_CLASS1_DLL(SotStorageStream,SotStorageStreamFactory,SotObject,
+ SvGlobalName( 0xd7deb420, 0xf902, 0x11d0,
+ 0xaa, 0xa1, 0x0, 0xa0, 0x24, 0x9d, 0x55, 0x90 ) )
+SO2_IMPL_INVARIANT(SotStorageStream)
+
+
+void SotStorageStream::TestMemberObjRef( BOOL /*bFree*/ )
+{
+}
+
+#ifdef TEST_INVARIANT
+void SotStorageStream::TestMemberInvariant( BOOL /*bPrint*/ )
+{
+}
+#endif
+
+/************************************************************************
+|* SotStorageStream::SotStorageStream()
+|*
+|* Beschreibung
+*************************************************************************/
+SvLockBytesRef MakeLockBytes_Impl( const String & rName, StreamMode nMode )
+{
+ SvLockBytesRef xLB;
+ if( rName.Len() )
+ {
+ SvStream * pFileStm = new SvFileStream( rName, nMode );
+ xLB = new SvLockBytes( pFileStm, TRUE );
+ }
+ else
+ {
+ SvStream * pCacheStm = new SvCacheStream();
+ xLB = new SvLockBytes( pCacheStm, TRUE );
+ }
+ return xLB;
+}
+
+SotStorageStream::SotStorageStream( const String & rName, StreamMode nMode,
+ StorageMode nStorageMode)
+ : SvStream( MakeLockBytes_Impl( rName, nMode ) )
+ , pOwnStm( NULL )
+{
+ if( nMode & STREAM_WRITE )
+ bIsWritable = TRUE;
+ else
+ bIsWritable = FALSE;
+
+ DBG_ASSERT( !nStorageMode,"StorageModes ignored" )
+}
+
+SotStorageStream::SotStorageStream( StorageStream * pStm )
+{
+ if( STREAM_WRITE & pStm->GetMode() )
+ bIsWritable = TRUE;
+ else
+ bIsWritable = FALSE;
+
+ pOwnStm = pStm;
+ SetError( pStm->GetError() );
+ pStm->ResetError();
+}
+
+SotStorageStream::SotStorageStream()
+ : pOwnStm( NULL )
+{
+ // ??? wenn Init virtuell ist, entsprechen setzen
+ bIsWritable = TRUE;
+}
+
+/************************************************************************
+|* SotStorageStream::~SotStorageStream()
+|*
+|* Beschreibung
+*************************************************************************/
+SotStorageStream::~SotStorageStream()
+{
+
+ SetBufferSize( 0 );
+ // Hack, wegen Fehler in den SD-Storages
+ // Commit();
+ delete pOwnStm;
+}
+
+/*************************************************************************
+|* SotStorageStream::SyncSvStream()
+|*
+|* Beschreibung: Der SvStream wird auf den Zustand des Standard-Streams
+|* gesetzt. Der Puffer des SvStreams wird weggeworfen.
+*************************************************************************/
+void SotStorageStream::SyncSvStream()
+{
+ ULONG nPos = 0;
+ if( pOwnStm )
+ {
+ pOwnStm->Flush();
+ nPos = pOwnStm->Tell();
+ SetError( pOwnStm->GetError() );
+ SvStream::SyncSvStream( nPos );
+ }
+}
+
+/*************************************************************************
+|* SotStorageStream::ResetError()
+|*
+|* Beschreibung
+*************************************************************************/
+void SotStorageStream::ResetError()
+{
+ SvStream::ResetError();
+ if( pOwnStm )
+ pOwnStm->ResetError();
+}
+
+/*************************************************************************
+|* SotStorageStream::GetData()
+|*
+|* Beschreibung
+*************************************************************************/
+ULONG SotStorageStream::GetData( void* pData, ULONG nSize )
+{
+ ULONG nRet = 0;
+
+ if( pOwnStm )
+ {
+ nRet = pOwnStm->Read( pData, nSize );
+ SetError( pOwnStm->GetError() );
+ }
+ else
+ nRet = SvStream::GetData( (sal_Char *)pData, nSize );
+ return nRet;
+}
+
+/*************************************************************************
+|* SotStorageStream::PutData()
+|*
+|* Beschreibung
+*************************************************************************/
+ULONG SotStorageStream::PutData( const void* pData, ULONG nSize )
+{
+ ULONG nRet = 0;
+
+ if( pOwnStm )
+ {
+ nRet = pOwnStm->Write( pData, nSize );
+ SetError( pOwnStm->GetError() );
+ }
+ else
+ nRet = SvStream::PutData( (sal_Char *)pData, nSize );
+ return nRet;
+}
+
+/*************************************************************************
+|* SotStorageStream::SeekPos()
+|*
+|* Beschreibung
+*************************************************************************/
+ULONG SotStorageStream::SeekPos( ULONG nPos )
+{
+ ULONG nRet = 0;
+
+ if( pOwnStm )
+ {
+ nRet = pOwnStm->Seek( nPos );
+ SetError( pOwnStm->GetError() );
+ }
+ else
+ nRet = SvStream::SeekPos( nPos );
+ return nRet;
+}
+
+/*************************************************************************
+|* SotStorageStream::Flush()
+|*
+|* Beschreibung
+*************************************************************************/
+void SotStorageStream::FlushData()
+{
+ if( pOwnStm )
+ {
+ pOwnStm->Flush();
+ SetError( pOwnStm->GetError() );
+ }
+ else
+ SvStream::FlushData();
+}
+
+/*************************************************************************
+|* SotStorageStream::SetSize()
+|*
+|* Beschreibung
+*************************************************************************/
+void SotStorageStream::SetSize( ULONG nNewSize )
+{
+ ULONG nPos = Tell();
+ if( pOwnStm )
+ {
+ pOwnStm->SetSize( nNewSize );
+ SetError( pOwnStm->GetError() );
+ }
+ else
+ SvStream::SetSize( nNewSize );
+
+ if( nNewSize < nPos )
+ // ans Ende setzen
+ Seek( nNewSize );
+
+ //return GetError() == SVSTREAM_OK;
+}
+
+/*************************************************************************
+|*
+|* SotStorageStream::GetSize()
+|*
+|* Beschreibung
+|*
+*************************************************************************/
+UINT32 SotStorageStream::GetSize() const
+{
+ ULONG nPos = Tell();
+ ((SotStorageStream *)this)->Seek( STREAM_SEEK_TO_END );
+ ULONG nSize = Tell();
+ ((SotStorageStream *)this)->Seek( nPos );
+ return nSize;
+}
+
+/*************************************************************************
+|* SotStorageStream::CopyTo()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorageStream::CopyTo( SotStorageStream * pDestStm )
+{
+ Flush(); // alle Daten schreiben
+ pDestStm->ClearBuffer();
+ if( !pOwnStm || !pDestStm->pOwnStm )
+ { // Wenn Ole2 oder nicht nur eigene StorageStreams
+
+ ULONG nPos = Tell(); // Position merken
+ pDestStm->SetSize( 0 ); // Ziel-Stream leeren
+
+ void * pMem = new BYTE[ 8192 ];
+ ULONG nRead;
+ while( 0 != (nRead = Read( pMem, 8192 )) )
+ {
+ if( nRead != pDestStm->Write( pMem, nRead ) )
+ {
+ SetError( SVSTREAM_GENERALERROR );
+ break;
+ }
+ }
+ delete pMem;
+ // Position setzen
+ pDestStm->Seek( nPos );
+ Seek( nPos );
+ }
+ else
+ {
+ /*
+ // Kopieren
+ nErr = pObjI->CopyTo( pDestStm->pObjI, uSize, NULL, &uWrite );
+ if( SUCCEEDED( nErr ) )
+ {
+ // Ziel-Streamzeiger steht hinter den Daten
+ // SvSeek abgleichen
+ pDestStm->Seek( uWrite.LowPart );
+ }
+ else if( GetScode( nErr ) == E_NOTIMPL )
+ { // Eines Tages werden alle MS... ?!#
+ */
+ pOwnStm->CopyTo( pDestStm->pOwnStm );
+ SetError( pOwnStm->GetError() );
+ }
+ return GetError() == SVSTREAM_OK;
+}
+
+/*************************************************************************
+|* SotStorageStream::Commit()
+|* SotStorageStream::Revert()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorageStream::Commit()
+{
+ if( pOwnStm )
+ {
+ pOwnStm->Flush();
+ if( pOwnStm->GetError() == SVSTREAM_OK )
+ pOwnStm->Commit();
+ SetError( pOwnStm->GetError() );
+ }
+ return GetError() == SVSTREAM_OK;
+}
+
+BOOL SotStorageStream::Revert()
+{
+ if( !pOwnStm )
+ {
+ pOwnStm->Revert();
+ SetError( pOwnStm->GetError() );
+ }
+ return GetError() == SVSTREAM_OK;
+}
+
+/************** class SotStorage ******************************************
+*************************************************************************/
+class SotStorageFactory : public SotFactory
+{
+public:
+ TYPEINFO();
+ SotStorageFactory( const SvGlobalName & rName,
+ const String & rClassName,
+ CreateInstanceType pCreateFuncP )
+ : SotFactory( rName, rClassName, pCreateFuncP )
+ {}
+};
+TYPEINIT1(SotStorageFactory,SotFactory);
+
+
+SO2_IMPL_BASIC_CLASS1_DLL(SotStorage,SotStorageFactory,SotObject,
+ SvGlobalName( 0x980ce7e0, 0xf905, 0x11d0,
+ 0xaa, 0xa1, 0x0, 0xa0, 0x24, 0x9d, 0x55, 0x90 ) )
+SO2_IMPL_INVARIANT(SotStorage)
+
+
+/************************************************************************
+|*
+|* SotStorage::Tes*()
+|*
+|* Beschreibung
+*************************************************************************/
+void SotStorage::TestMemberObjRef( BOOL /*bFree*/ )
+{
+}
+
+#ifdef TEST_INVARIANT
+void SotStorage::TestMemberInvariant( BOOL bPrint )
+{
+}
+#endif
+
+/************************************************************************
+|*
+|* SotStorage::SotStorage()
+|*
+|* Beschreibung Es muss ein I... Objekt an SvObject uebergeben
+|* werden, da es sonst selbst ein IUnknown anlegt und
+|* festlegt, dass alle weiteren I... Objekte mit
+|* delete zerstoert werden (Owner() == TRUE).
+|* Es werden aber nur IStorage Objekte benutzt und nicht
+|* selbst implementiert, deshalb wird so getan, als ob
+|* das IStorage Objekt von aussen kam und es wird mit
+|* Release() freigegeben.
+|* Die CreateStorage Methoden werden benoetigt, um
+|* ein IStorage Objekt vor dem Aufruf von SvObject
+|* zu erzeugen (Own, !Own automatik).
+|* Hat CreateStorage ein Objekt erzeugt, dann wurde
+|* der RefCounter schon um 1 erhoet.
+|* Die Uebergabe erfolgt in pStorageCTor. Die Variable
+|* ist NULL, wenn es nicht geklappt hat.
+|* Ersterstellung MM 23.06.94
+|* Letzte Aenderung MM 23.06.94
+|*
+*************************************************************************/
+#define INIT_SotStorage() \
+ : nError( SVSTREAM_OK ) \
+ , bIsRoot( FALSE ) \
+ , bDelStm( FALSE ) \
+ , nVersion( SOFFICE_FILEFORMAT_NOW ) \
+ , pTmpStg( NULL ) \
+ , pOwnStg( NULL ) \
+ , pStorStm( NULL )
+
+SotStorage::SotStorage()
+ INIT_SotStorage()
+{
+}
+
+#define ERASEMASK ( STREAM_TRUNC | STREAM_WRITE | STREAM_SHARE_DENYALL )
+
+SotStorage::SotStorage( const String & rName, StreamMode nMode,
+ StorageMode nStorageMode )
+ INIT_SotStorage()
+{
+ aName = rName; // Namen merken
+ // Sicherheitshalber wird die Storage File geloescht, wenn
+ // sie neu erzeugt werden soll
+ if( aName.Len() && ( ( nMode & ERASEMASK ) == ERASEMASK ) )
+ {
+ DirEntry aFile( rName );
+ aFile.Kill();
+ }
+
+ pTmpStg = new Storage( aName, nMode,
+ (nStorageMode & STORAGE_TRANSACTED) ? FALSE : TRUE );
+ pOwnStg = pTmpStg;
+ if( !aName.Len() )
+ aName = pOwnStg->GetName();
+ ULONG nErr = pOwnStg->GetError();
+ SetError( nErr );
+}
+
+SotStorage::SotStorage( Storage * pStor )
+ INIT_SotStorage()
+{
+ aName = pStor->GetName(); // Namen merken
+ SignAsRoot( pStor->IsRoot() );
+ SetError( pStor->GetError() );
+ pOwnStg = pStor;
+ ULONG nErr = pOwnStg->GetError();
+ SetError( nErr );
+}
+
+SotStorage::SotStorage( SvStream & rStm )
+ INIT_SotStorage()
+{
+ SetError( rStm.GetError() );
+ pOwnStg = new Storage( rStm, FALSE );
+}
+
+SotStorage::SotStorage( SvStream * pStm, BOOL bDelete )
+ INIT_SotStorage()
+{
+ SetError( pStm->GetError() );
+ pOwnStg = new Storage( *pStm, FALSE );
+
+ ULONG nError = pOwnStg->GetError();
+ if ( nError != SVSTREAM_OK )
+ SetError( nError );
+
+ pStorStm = pStm;
+ bDelStm = bDelete;
+}
+
+/*************************************************************************
+|* SotStorage::~SotStorage()
+|*
+|* Beschreibung
+*************************************************************************/
+SotStorage::~SotStorage()
+{
+ delete pOwnStg;
+ if( bDelStm )
+ delete pStorStm;
+}
+
+
+/*************************************************************************
+|* SotStorage::CreateMemoryStream()
+|*
+|* Beschreibung
+*************************************************************************/
+SvMemoryStream * SotStorage::CreateMemoryStream()
+{
+ SvMemoryStream * pStm = NULL;
+ pStm = new SvMemoryStream( 0x8000, 0x8000 );
+ SotStorageRef aStg = new SotStorage( *pStm );
+ if( CopyTo( aStg ) )
+ aStg->Commit();
+ else
+ {
+ aStg.Clear(); // Storage vorher freigeben
+ delete pStm;
+ }
+ return pStm;
+}
+
+/*************************************************************************
+|* SotStorage::GetStorage()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorage::IsStorageFile( const String & rFileName )
+{
+ return Storage::IsStorageFile( rFileName );
+}
+
+/*************************************************************************
+|* SotStorage::GetStorage()
+|*
+|* Beschreibung
+*************************************************************************/
+const String & SotStorage::GetName() const
+{
+ if( !aName.Len() )
+ {
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ ((SotStorage *)this)->aName = pOwnStg->GetName();
+ }
+ return aName;
+}
+
+void SotStorage::SetName( const String& rName )
+{
+ // This method is necessary because most storages will not be opened with a FileName, but an external stream instead
+ // This stream is a stream opened by a UCP and so aName is only used as a transport for all client code of the SotStorage
+ // class that depends on the fact that a root storage has a name
+ DBG_ASSERT( !GetName().Len(), "SetName() must not be called when the storage already has a name!" );
+ aName = rName;
+}
+
+/*************************************************************************
+|* SotStorage::ResetError()
+|*
+|* Beschreibung
+*************************************************************************/
+void SotStorage::ResetError()
+{
+ nError = SVSTREAM_OK;
+ if( pOwnStg )
+ pOwnStg->ResetError();
+}
+
+/*************************************************************************
+|* SotStorage::SetClass()
+|* SotStorage::SetConvertClass()
+|*
+|* Beschreibung
+*************************************************************************/
+void SotStorage::SetClass( const SvGlobalName & rName,
+ ULONG nOriginalClipFormat,
+ const String & rUserTypeName )
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ pOwnStg->SetClass( rName, nOriginalClipFormat, rUserTypeName );
+ else
+ SetError( SVSTREAM_GENERALERROR );
+}
+
+void SotStorage::SetConvertClass( const SvGlobalName & rName,
+ ULONG nOriginalClipFormat,
+ const String & rUserTypeName )
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ pOwnStg->SetConvertClass( rName, nOriginalClipFormat, rUserTypeName );
+ else
+ SetError( SVSTREAM_GENERALERROR );
+}
+
+/*************************************************************************
+|* SotStorage::GetClassName()
+|* SotStorage::GetFormat()
+|* SotStorage::GetUserName()
+|* SotStorage::ShouldConvert()
+|*
+|* Beschreibung
+*************************************************************************/
+SvGlobalName SotStorage::GetClassName()
+{
+ SvGlobalName aGN;
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ aGN = pOwnStg->GetClassName();
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return aGN;
+}
+
+ULONG SotStorage::GetFormat()
+{
+ ULONG nFormat = 0;
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ nFormat = pOwnStg->GetFormat();
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return nFormat;
+}
+
+String SotStorage::GetUserName()
+{
+ String aName;
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ aName = pOwnStg->GetUserName();
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return aName;
+}
+
+BOOL SotStorage::ShouldConvert()
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ return pOwnStg->ShouldConvert();
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return FALSE;
+}
+
+/*************************************************************************
+|* SotStorage::FillInfoList()
+|*
+|* Beschreibung
+*************************************************************************/
+void SotStorage::FillInfoList( SvStorageInfoList * pFillList ) const
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ pOwnStg->FillInfoList( pFillList );
+}
+
+/*************************************************************************
+|* SotStorage::CopyTo()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorage::CopyTo( SotStorage * pDestStg )
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ DBG_ASSERT( pDestStg->Owner(), "must be owner" )
+ if( pOwnStg && pDestStg->pOwnStg )
+ {
+ pOwnStg->CopyTo( pDestStg->pOwnStg );
+ SetError( pOwnStg->GetError() );
+ pDestStg->aKey = aKey;
+ pDestStg->nVersion = nVersion;
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return SVSTREAM_OK == GetError();
+}
+
+/*************************************************************************
+|* SotStorage::Commit()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorage::Commit()
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ {
+ if( !pOwnStg->Commit() )
+ SetError( pOwnStg->GetError() );
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return SVSTREAM_OK == GetError();
+}
+
+/*************************************************************************
+|* SotStorage::Revert()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorage::Revert()
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ {
+ if( !pOwnStg->Revert() )
+ SetError( pOwnStg->GetError() );
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return SVSTREAM_OK == GetError();
+}
+
+/*************************************************************************
+|* SotStorage::OpenStream()
+|*
+|* Beschreibung
+*************************************************************************/
+SotStorageStream * SotStorage::OpenSotStream( const String & rEleName,
+ StreamMode nMode,
+ StorageMode nStorageMode )
+{
+ DBG_ASSERT( !nStorageMode, "StorageModes ignored" )
+
+ SotStorageStream * pStm = NULL;
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ {
+ // volle Ole-Patches einschalten
+ // egal was kommt, nur exclusiv gestattet
+ nMode |= STREAM_SHARE_DENYALL;
+ ErrCode nE = pOwnStg->GetError();
+ StorageStream * p = pOwnStg->OpenStream( rEleName, nMode,
+ (nStorageMode & STORAGE_TRANSACTED) ? FALSE : TRUE );
+ pStm = new SotStorageStream( p );
+ if( !nE )
+ pOwnStg->ResetError(); // kein Fehler setzen
+ if( nMode & STREAM_TRUNC )
+ pStm->SetSize( 0 );
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return pStm;
+}
+
+/*************************************************************************
+|* SotStorage::OpenStorage()
+|*
+|* Beschreibung
+*************************************************************************/
+SotStorage * SotStorage::OpenSotStorage( const String & rEleName,
+ StreamMode nMode,
+ StorageMode nStorageMode )
+{
+ SotStorage * pStor = NULL;
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ {
+ nMode |= STREAM_SHARE_DENYALL;
+ ErrCode nE = pOwnStg->GetError();
+ Storage * p = pOwnStg->OpenStorage( rEleName, nMode,
+ (nStorageMode & STORAGE_TRANSACTED) ? FALSE : TRUE );
+ pStor = new SotStorage( p );
+ if( !nE )
+ pOwnStg->ResetError(); // kein Fehler setzen
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return pStor;
+}
+
+/*************************************************************************
+|* SotStorage::IsStream()
+|* SotStorage::IsStorage()
+|* SotStorage::IsContained()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorage::IsStorage( const String & rEleName ) const
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ // ein bisschen schneller
+ if( pOwnStg )
+ return pOwnStg->IsStorage( rEleName );
+ return FALSE;
+}
+
+BOOL SotStorage::IsStream( const String & rEleName ) const
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ // ein bisschen schneller
+ if( pOwnStg )
+ return pOwnStg->IsStream( rEleName );
+ return FALSE;
+}
+
+BOOL SotStorage::IsContained( const String & rEleName ) const
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ // ein bisschen schneller
+ if( pOwnStg )
+ return pOwnStg->IsContained( rEleName );
+ return FALSE;
+}
+
+/*************************************************************************
+|* SotStorage::Remove()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorage::Remove( const String & rEleName )
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ {
+ pOwnStg->Remove( rEleName );
+ SetError( pOwnStg->GetError() );
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return SVSTREAM_OK == GetError();
+}
+
+/*************************************************************************
+|* SotStorage::Rename()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorage::Rename( const String & rEleName, const String & rNewName )
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ {
+ pOwnStg->Rename( rEleName, rNewName );
+ SetError( pOwnStg->GetError() );
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return SVSTREAM_OK == GetError();
+}
+
+/*************************************************************************
+|* SotStorage::CopyTo()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorage::CopyTo( const String & rEleName,
+ SotStorage * pNewSt, const String & rNewName )
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ DBG_ASSERT( pNewSt->Owner(), "must be owner" )
+ if( pOwnStg )
+ {
+ pOwnStg->CopyTo( rEleName, pNewSt->pOwnStg, rNewName );
+ SetError( pOwnStg->GetError() );
+ SetError( pNewSt->GetError() );
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return SVSTREAM_OK == GetError();
+}
+
+/*************************************************************************
+|* SotStorage::MoveTo()
+|*
+|* Beschreibung
+*************************************************************************/
+BOOL SotStorage::MoveTo( const String & rEleName,
+ SotStorage * pNewSt, const String & rNewName )
+{
+ DBG_ASSERT( Owner(), "must be owner" )
+ DBG_ASSERT( pNewSt->Owner(), "must be owner" )
+ if( pOwnStg )
+ {
+ pOwnStg->MoveTo( rEleName, pNewSt->pOwnStg, rNewName );
+ SetError( pOwnStg->GetError() );
+ SetError( pNewSt->GetError() );
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return SVSTREAM_OK == GetError();
+}
+
+const SvStream* SotStorage::GetSvStream()
+{
+ const SvStream* pResult = 0;
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ pResult = pOwnStg->GetSvStream();
+ return pResult;
+}
+
+SvStream* SotStorage::GetTargetSvStream() const
+{
+ SvStream* pResult = 0;
+ DBG_ASSERT( Owner(), "must be owner" )
+ if( pOwnStg )
+ pResult = (SvStream*)(pOwnStg->GetSvStream());
+ return pResult;
+}
+
+
+BOOL SotStorage::Validate()
+{
+ DBG_ASSERT( bIsRoot, "Validate nur an Rootstorage" );
+ if( pOwnStg )
+ return pOwnStg->ValidateFAT();
+ else
+ return TRUE;
+}
+
+
diff --git a/sot/source/sdstor/storinfo.cxx b/sot/source/sdstor/storinfo.cxx
new file mode 100644
index 000000000000..04aef46f9bab
--- /dev/null
+++ b/sot/source/sdstor/storinfo.cxx
@@ -0,0 +1,143 @@
+/*************************************************************************
+ *
+ * $RCSfile: storinfo.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:56:52 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <stg.hxx>
+#include <storinfo.hxx>
+#include <exchange.hxx>
+#pragma hdrstop
+
+
+/************** class SvStorageInfoList **********************************
+*************************************************************************/
+PRV_SV_IMPL_OWNER_LIST(SvStorageInfoList,SvStorageInfo)
+
+const SvStorageInfo * SvStorageInfoList::Get( const String & rEleName )
+{
+ for( ULONG i = 0; i < Count(); i++ )
+ {
+ const SvStorageInfo & rType = GetObject( i );
+ if( rType.GetName() == rEleName )
+ return &rType;
+ }
+ return NULL;
+}
+
+/************** class SvStorageInfo **************************************
+*************************************************************************/
+ULONG ReadClipboardFormat( SvStream & rStm )
+{
+ ULONG nFormat = 0;
+ INT32 nLen = 0;
+ rStm >> nLen;
+ if( rStm.IsEof() )
+ rStm.SetError( SVSTREAM_GENERALERROR );
+ if( nLen > 0 )
+ {
+ // get a string name
+ sal_Char * p = new sal_Char[ nLen ];
+ if( rStm.Read( p, nLen ) == (ULONG) nLen )
+ {
+ nFormat = SotExchange::RegisterFormatName( String::CreateFromAscii( p, nLen -1 ) );
+ }
+ else
+ rStm.SetError( SVSTREAM_GENERALERROR );
+ delete p;
+ }
+ else if( nLen == -1L )
+ // Windows clipboard format
+ // SV und Win stimmen ueberein (bis einschl. FORMAT_GDIMETAFILE)
+ rStm >> nFormat;
+ else if( nLen == -2L )
+ {
+ rStm >> nFormat;
+ // Mac clipboard format
+ // ??? not implemented
+ rStm.SetError( SVSTREAM_GENERALERROR );
+ }
+ else if( nLen != 0 )
+ {
+ // unknown identifier
+ rStm.SetError( SVSTREAM_GENERALERROR );
+ }
+ return nFormat;
+}
+
+void WriteClipboardFormat( SvStream & rStm, ULONG nFormat )
+{
+ // determine the clipboard format string
+ String aCbFmt;
+ if( nFormat > FORMAT_GDIMETAFILE )
+ aCbFmt = SotExchange::GetFormatName( nFormat );
+ if( aCbFmt.Len() )
+ {
+ ByteString aAsciiCbFmt( aCbFmt, RTL_TEXTENCODING_ASCII_US );
+ rStm << (INT32) (aAsciiCbFmt.Len() + 1);
+ rStm << (const char *)aAsciiCbFmt.GetBuffer();
+ rStm << (UINT8) 0;
+ }
+ else if( nFormat )
+ rStm << (INT32) -1 // for Windows
+ << (INT32) nFormat;
+ else
+ rStm << (INT32) 0; // no clipboard format
+}
+
+