| /************************************************************** |
| * |
| * 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; |
| } |