diff options
Diffstat (limited to 'sot/source/sdstor/stgelem.cxx')
-rw-r--r-- | sot/source/sdstor/stgelem.cxx | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/sot/source/sdstor/stgelem.cxx b/sot/source/sdstor/stgelem.cxx new file mode 100644 index 000000000000..ed29ca8305a8 --- /dev/null +++ b/sot/source/sdstor/stgelem.cxx @@ -0,0 +1,428 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: stgelem.cxx,v $ + * $Revision: 1.12.6.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sot.hxx" + +#include <string.h> // memset(), memcpy() +#include <rtl/ustring.hxx> +#include <com/sun/star/lang/Locale.hpp> +#include <unotools/charclass.hxx> +#include "stg.hxx" +#include "stgelem.hxx" +#include "stgcache.hxx" +#include "stgstrms.hxx" +#include "stgdir.hxx" +#include "stgio.hxx" + +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(); + Load( r ); + return rIo.Good(); +} + +BOOL StgHeader::Load( SvStream& r ) +{ + 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 r.GetErrorCode() == ERRCODE_NONE; +} + +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 ); +} + +static bool lcl_wontoverflow(short shift) +{ + return shift >= 0 && shift < (short)sizeof(short) * 8 - 1; +} + +// Perform thorough checks also on unknown variables +BOOL StgHeader::Check() +{ + return BOOL( memcmp( cSignature, cStgSignature, 8 ) == 0 + && (short) ( nVersion >> 16 ) == 3 ) + && lcl_wontoverflow(nPageSize) + && lcl_wontoverflow(nDataPageSize); +} + +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 String ToUpperUnicode( const String & rStr ) +{ + // I don't know the locale, so en_US is hopefully fine + /* + com.sun.star.lang.Locale aLocale; + aLocale.Language = OUString::createFromAscii( "en" ); + aLocale.Country = OUString::createFromAscii( "US" ); + */ + static rtl::OUString aEN=rtl::OUString::createFromAscii( "en" ); + static rtl::OUString aUS=rtl::OUString::createFromAscii( "US" ); + static CharClass aCC( com::sun::star::lang::Locale( aEN, aUS, rtl::OUString() ) ); + return aCC.toUpper( rStr, 0, rStr.Len() ); +} + + +BOOL StgEntry::SetName( const String& rName ) +{ + // I don't know the locale, so en_US is hopefully fine + aName = ToUpperUnicode( rName ); + aName.Erase( 31 ); + + int i; + for( i = 0; i < aName.Len() && i < 32; i++ ) + nName[ i ] = rName.GetChar( sal_uInt16( 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 || (nSize < 0 && cType != STG_STORAGE) ) + { + // the size makes no sence for the substorage + // TODO/LATER: actually the size should be an unsigned value, but in this case it would mean a stream of more than 2Gb + return FALSE; + } + + aName = String( nName, n ); + // I don't know the locale, so en_US is hopefully fine + aName = ToUpperUnicode( aName ); + aName.Erase( 31 ); + + 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 +} + |