blob: b1b26219a3177bcbd2b11a7339bd1db974030b36 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"
#include <tools/stream.hxx>
#include <tools/tenccvt.hxx>
#include <basic/sbx.hxx>
#include "sb.hxx"
#include <string.h> // memset() etc
#include "image.hxx"
#include <codegen.hxx>
SbiImage::SbiImage()
{
pStringOff = NULL;
pStrings = NULL;
pCode = NULL;
pLegacyPCode = NULL;
nFlags = 0;
nStrings = 0;
nStringSize= 0;
nCodeSize = 0;
nLegacyCodeSize =
nDimBase = 0;
bInit =
bError = sal_False;
bFirstInit = sal_True;
eCharSet = gsl_getSystemTextEncoding();
}
SbiImage::~SbiImage()
{
Clear();
}
void SbiImage::Clear()
{
delete[] pStringOff;
delete[] pStrings;
delete[] pCode;
ReleaseLegacyBuffer();
pStringOff = NULL;
pStrings = NULL;
pCode = NULL;
nFlags = 0;
nStrings = 0;
nStringSize= 0;
nLegacyCodeSize = 0;
nCodeSize = 0;
eCharSet = gsl_getSystemTextEncoding();
nDimBase = 0;
bError = sal_False;
}
/**************************************************************************
*
* Service-Routines for Load/Store
*
**************************************************************************/
sal_Bool SbiGood( SvStream& r )
{
return sal_Bool( !r.IsEof() && r.GetError() == SVSTREAM_OK );
}
// Open Record
sal_uIntPtr SbiOpenRecord( SvStream& r, sal_uInt16 nSignature, sal_uInt16 nElem )
{
sal_uIntPtr nPos = r.Tell();
r << nSignature << (sal_Int32) 0 << nElem;
return nPos;
}
// Close Record
void SbiCloseRecord( SvStream& r, sal_uIntPtr nOff )
{
sal_uIntPtr nPos = r.Tell();
r.Seek( nOff + 2 );
r << (sal_Int32) ( nPos - nOff - 8 );
r.Seek( nPos );
}
/**************************************************************************
*
* Load/Store
*
**************************************************************************/
// If the version number does not find, binary parts are omitted, but not
// source, comments and name
sal_Bool SbiImage::Load( SvStream& r )
{
sal_uInt32 nVersion = 0; // Versionsnumber
return Load( r, nVersion );
}
sal_Bool SbiImage::Load( SvStream& r, sal_uInt32& nVersion )
{
sal_uInt16 nSign, nCount;
sal_uInt32 nLen, nOff;
Clear();
// Read Master-Record
r >> nSign >> nLen >> nCount;
sal_uIntPtr nLast = r.Tell() + nLen;
sal_uInt32 nCharSet; // System charset
sal_uInt32 lDimBase;
sal_uInt16 nReserved1;
sal_uInt32 nReserved2;
sal_uInt32 nReserved3;
sal_Bool bBadVer = sal_False;
if( nSign == B_MODULE )
{
r >> nVersion >> nCharSet >> lDimBase
>> nFlags >> nReserved1 >> nReserved2 >> nReserved3;
eCharSet = (CharSet) nCharSet;
eCharSet = GetSOLoadTextEncoding( eCharSet );
bBadVer = sal_Bool( nVersion > B_CURVERSION );
nDimBase = (sal_uInt16) lDimBase;
}
bool bLegacy = ( nVersion < B_EXT_IMG_VERSION );
sal_uIntPtr nNext;
while( ( nNext = r.Tell() ) < nLast )
{
short i;
r >> nSign >> nLen >> nCount;
nNext += nLen + 8;
if( r.GetError() == SVSTREAM_OK )
switch( nSign )
{
case B_NAME:
r.ReadByteString( aName, eCharSet );
//r >> aName;
break;
case B_COMMENT:
r.ReadByteString( aComment, eCharSet );
//r >> aComment;
break;
case B_SOURCE:
{
String aTmp;
r.ReadByteString( aTmp, eCharSet );
aOUSource = aTmp;
//r >> aSource;
break;
}
#ifdef EXTENDED_BINARY_MODULES
case B_EXTSOURCE:
{
for( sal_uInt16 j = 0 ; j < nCount ; j++ )
{
String aTmp;
r.ReadByteString( aTmp, eCharSet );
aOUSource += aTmp;
}
break;
}
#endif
case B_PCODE:
if( bBadVer ) break;
pCode = new char[ nLen ];
nCodeSize = nLen;
r.Read( pCode, nCodeSize );
if ( bLegacy )
{
ReleaseLegacyBuffer(); // release any previously held buffer
nLegacyCodeSize = (sal_uInt16) nCodeSize;
pLegacyPCode = pCode;
PCodeBuffConvertor< sal_uInt16, sal_uInt32 > aLegacyToNew( (sal_uInt8*)pLegacyPCode, nLegacyCodeSize );
aLegacyToNew.convert();
pCode = (char*)aLegacyToNew.GetBuffer();
nCodeSize = aLegacyToNew.GetSize();
// we don't release the legacy buffer
// right now, thats because the module
// needs it to fix up the method
// nStart members. When that is done
// the module can release the buffer
// or it can wait until this routine
// is called again or when this class // destructs all of which will trigger
// release of the buffer.
}
break;
case B_PUBLICS:
case B_POOLDIR:
case B_SYMPOOL:
case B_LINERANGES:
break;
case B_STRINGPOOL:
if( bBadVer ) break;
MakeStrings( nCount );
for( i = 0; i < nStrings && SbiGood( r ); i++ )
{
r >> nOff;
pStringOff[ i ] = (sal_uInt16) nOff;
}
r >> nLen;
if( SbiGood( r ) )
{
delete [] pStrings;
pStrings = new sal_Unicode[ nLen ];
nStringSize = (sal_uInt16) nLen;
char* pByteStrings = new char[ nLen ];
r.Read( pByteStrings, nStringSize );
for( short j = 0; j < nStrings; j++ )
{
sal_uInt16 nOff2 = (sal_uInt16) pStringOff[ j ];
String aStr( pByteStrings + nOff2, eCharSet );
memcpy( pStrings + nOff2, aStr.GetBuffer(), (aStr.Len() + 1) * sizeof( sal_Unicode ) );
}
delete[] pByteStrings;
} break;
case B_MODEND:
goto done;
default:
break;
}
else
break;
r.Seek( nNext );
}
done:
r.Seek( nLast );
//if( eCharSet != ::GetSystemCharSet() )
//ConvertStrings();
if( !SbiGood( r ) )
bError = sal_True;
return sal_Bool( !bError );
}
sal_Bool SbiImage::Save( SvStream& r, sal_uInt32 nVer )
{
bool bLegacy = ( nVer < B_EXT_IMG_VERSION );
// detect if old code exceeds legacy limits
// if so, then disallow save
if ( bLegacy && ExceedsLegacyLimits() )
{
SbiImage aEmptyImg;
aEmptyImg.aName = aName;
aEmptyImg.Save( r, B_LEGACYVERSION );
return sal_True;
}
// First of all the header
sal_uIntPtr nStart = SbiOpenRecord( r, B_MODULE, 1 );
sal_uIntPtr nPos;
eCharSet = GetSOStoreTextEncoding( eCharSet );
if ( bLegacy )
r << (sal_Int32) B_LEGACYVERSION;
else
r << (sal_Int32) B_CURVERSION;
r << (sal_Int32) eCharSet
<< (sal_Int32) nDimBase
<< (sal_Int16) nFlags
<< (sal_Int16) 0
<< (sal_Int32) 0
<< (sal_Int32) 0;
// Name?
if( aName.Len() && SbiGood( r ) )
{
nPos = SbiOpenRecord( r, B_NAME, 1 );
r.WriteByteString( aName, eCharSet );
//r << aName;
SbiCloseRecord( r, nPos );
}
// Comment?
if( aComment.Len() && SbiGood( r ) )
{
nPos = SbiOpenRecord( r, B_COMMENT, 1 );
r.WriteByteString( aComment, eCharSet );
//r << aComment;
SbiCloseRecord( r, nPos );
}
// Source?
if( !aOUSource.isEmpty() && SbiGood( r ) )
{
nPos = SbiOpenRecord( r, B_SOURCE, 1 );
String aTmp;
sal_Int32 nLen = aOUSource.getLength();
const sal_Int32 nMaxUnitSize = STRING_MAXLEN - 1;
if( nLen > STRING_MAXLEN )
aTmp = aOUSource.copy( 0, nMaxUnitSize );
else
aTmp = aOUSource;
r.WriteByteString( aTmp, eCharSet );
//r << aSource;
SbiCloseRecord( r, nPos );
#ifdef EXTENDED_BINARY_MODULES
if( nLen > STRING_MAXLEN )
{
sal_Int32 nRemainingLen = nLen - nMaxUnitSize;
sal_uInt16 nUnitCount = sal_uInt16( (nRemainingLen + nMaxUnitSize - 1) / nMaxUnitSize );
nPos = SbiOpenRecord( r, B_EXTSOURCE, nUnitCount );
for( sal_uInt16 i = 0 ; i < nUnitCount ; i++ )
{
sal_Int32 nCopyLen =
(nRemainingLen > nMaxUnitSize) ? nMaxUnitSize : nRemainingLen;
String aTmp2 = aOUSource.copy( (i+1) * nMaxUnitSize, nCopyLen );
nRemainingLen -= nCopyLen;
r.WriteByteString( aTmp2, eCharSet );
}
SbiCloseRecord( r, nPos );
}
#endif
}
// Binary data?
if( pCode && SbiGood( r ) )
{
nPos = SbiOpenRecord( r, B_PCODE, 1 );
if ( bLegacy )
{
ReleaseLegacyBuffer(); // release any previously held buffer
PCodeBuffConvertor< sal_uInt32, sal_uInt16 > aNewToLegacy( (sal_uInt8*)pCode, nCodeSize );
aNewToLegacy.convert();
pLegacyPCode = (char*)aNewToLegacy.GetBuffer();
nLegacyCodeSize = aNewToLegacy.GetSize();
r.Write( pLegacyPCode, nLegacyCodeSize );
}
else
r.Write( pCode, nCodeSize );
SbiCloseRecord( r, nPos );
}
// String-Pool?
if( nStrings )
{
nPos = SbiOpenRecord( r, B_STRINGPOOL, nStrings );
// For every String:
// sal_uInt32 Offset of the Strings in the Stringblock
short i;
for( i = 0; i < nStrings && SbiGood( r ); i++ )
r << (sal_uInt32) pStringOff[ i ];
// Then the String-Block
char* pByteStrings = new char[ nStringSize ];
for( i = 0; i < nStrings; i++ )
{
sal_uInt16 nOff = (sal_uInt16) pStringOff[ i ];
ByteString aStr( pStrings + nOff, eCharSet );
memcpy( pByteStrings + nOff, aStr.GetBuffer(), (aStr.Len() + 1) * sizeof( char ) );
}
r << (sal_uInt32) nStringSize;
r.Write( pByteStrings, nStringSize );
delete[] pByteStrings;
SbiCloseRecord( r, nPos );
}
// Set overall length
SbiCloseRecord( r, nStart );
if( !SbiGood( r ) )
bError = sal_True;
return sal_Bool( !bError );
}
/**************************************************************************
*
* Routines called by the compiler
*
**************************************************************************/
void SbiImage::MakeStrings( short nSize )
{
nStrings = 0;
nStringIdx = 0;
nStringOff = 0;
nStringSize = 1024;
pStrings = new sal_Unicode[ nStringSize ];
pStringOff = new sal_uInt32[ nSize ];
if( pStrings && pStringOff )
{
nStrings = nSize;
memset( pStringOff, 0, nSize * sizeof( sal_uInt32 ) );
memset( pStrings, 0, nStringSize * sizeof( sal_Unicode ) );
}
else
bError = sal_True;
}
// Hinzufuegen eines Strings an den StringPool. Der String-Puffer
// waechst dynamisch in 1K-Schritten
// Add a string to StringPool. The String buffer is dynamically
// growing in 1K-Steps
void SbiImage::AddString( const String& r )
{
if( nStringIdx >= nStrings )
bError = sal_True;
if( !bError )
{
xub_StrLen len = r.Len() + 1;
sal_uInt32 needed = nStringOff + len;
if( needed > 0xFFFFFF00L )
bError = sal_True; // out of mem!
else if( needed > nStringSize )
{
sal_uInt32 nNewLen = needed + 1024;
nNewLen &= 0xFFFFFC00; // trim to 1K border
if( nNewLen > 0xFFFFFF00L )
nNewLen = 0xFFFFFF00L;
sal_Unicode* p = NULL;
if( (p = new sal_Unicode[ nNewLen ]) != NULL )
{
memcpy( p, pStrings, nStringSize * sizeof( sal_Unicode ) );
delete[] pStrings;
pStrings = p;
nStringSize = sal::static_int_cast< sal_uInt16 >(nNewLen);
}
else
bError = sal_True;
}
if( !bError )
{
pStringOff[ nStringIdx++ ] = nStringOff;
//ByteString aByteStr( r, eCharSet );
memcpy( pStrings + nStringOff, r.GetBuffer(), len * sizeof( sal_Unicode ) );
nStringOff = nStringOff + len;
// Last String? The update the size of the buffer
if( nStringIdx >= nStrings )
nStringSize = nStringOff;
}
}
}
// Add code block
// The block was fetched by the compiler from class SbBuffer and
// is already created with new. Additionally it contains all Integers
// in Big Endian format, so can be directly read/written.
void SbiImage::AddCode( char* p, sal_uInt32 s )
{
pCode = p;
nCodeSize = s;
}
// Add user type
void SbiImage::AddType(SbxObject* pObject)
{
if( !rTypes.Is() )
rTypes = new SbxArray;
SbxObject *pCopyObject = new SbxObject(*pObject);
rTypes->Insert (pCopyObject,rTypes->Count());
}
void SbiImage::AddEnum(SbxObject* pObject) // Register enum type
{
if( !rEnums.Is() )
rEnums = new SbxArray;
rEnums->Insert( pObject, rEnums->Count() );
}
/**************************************************************************
*
* Accessing the image
*
**************************************************************************/
// Note: IDs start with 1
String SbiImage::GetString( short nId ) const
{
if( nId && nId <= nStrings )
{
sal_uInt32 nOff = pStringOff[ nId - 1 ];
sal_Unicode* pStr = pStrings + nOff;
// #i42467: Special treatment for vbNullChar
if( *pStr == 0 )
{
sal_uInt32 nNextOff = (nId < nStrings) ? pStringOff[ nId ] : nStringOff;
sal_uInt32 nLen = nNextOff - nOff - 1;
if( nLen == 1 )
{
// Force length 1 and make char 0 afterwards
String aNullCharStr( String::CreateFromAscii( " " ) );
aNullCharStr.SetChar( 0, 0 );
return aNullCharStr;
}
}
else
{
String aStr( pStr );
return aStr;
}
}
return String();
}
const SbxObject* SbiImage::FindType (String aTypeName) const
{
return rTypes.Is() ? (SbxObject*)rTypes->Find(aTypeName,SbxCLASS_OBJECT) : NULL;
}
sal_uInt16 SbiImage::CalcLegacyOffset( sal_Int32 nOffset )
{
return SbiCodeGen::calcLegacyOffSet( (sal_uInt8*)pCode, nOffset ) ;
}
sal_uInt32 SbiImage::CalcNewOffset( sal_Int16 nOffset )
{
return SbiCodeGen::calcNewOffSet( (sal_uInt8*)pLegacyPCode, nOffset ) ;
}
void SbiImage::ReleaseLegacyBuffer()
{
delete[] pLegacyPCode;
pLegacyPCode = NULL;
nLegacyCodeSize = 0;
}
sal_Bool SbiImage::ExceedsLegacyLimits()
{
if ( ( nStringSize > 0xFF00L ) || ( CalcLegacyOffset( nCodeSize ) > 0xFF00L ) )
return sal_True;
return sal_False;
}