|  | /************************************************************** | 
|  | * | 
|  | * 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, that's 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; | 
|  | } |