1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_basic.hxx" 26 #include <tools/stream.hxx> 27 #include <tools/tenccvt.hxx> 28 #include <basic/sbx.hxx> 29 #include "sb.hxx" 30 #include <string.h> // memset() etc 31 #include "image.hxx" 32 #include <codegen.hxx> 33 SbiImage::SbiImage() 34 { 35 pStringOff = NULL; 36 pStrings = NULL; 37 pCode = NULL; 38 pLegacyPCode = NULL; 39 nFlags = 0; 40 nStrings = 0; 41 nStringSize= 0; 42 nCodeSize = 0; 43 nLegacyCodeSize = 44 nDimBase = 0; 45 bInit = 46 bError = sal_False; 47 bFirstInit = sal_True; 48 eCharSet = gsl_getSystemTextEncoding(); 49 } 50 51 SbiImage::~SbiImage() 52 { 53 Clear(); 54 } 55 56 void SbiImage::Clear() 57 { 58 delete[] pStringOff; 59 delete[] pStrings; 60 delete[] pCode; 61 ReleaseLegacyBuffer(); 62 pStringOff = NULL; 63 pStrings = NULL; 64 pCode = NULL; 65 nFlags = 0; 66 nStrings = 0; 67 nStringSize= 0; 68 nLegacyCodeSize = 0; 69 nCodeSize = 0; 70 eCharSet = gsl_getSystemTextEncoding(); 71 nDimBase = 0; 72 bError = sal_False; 73 } 74 75 /************************************************************************** 76 * 77 * Service-Routines for Load/Store 78 * 79 **************************************************************************/ 80 81 sal_Bool SbiGood( SvStream& r ) 82 { 83 return sal_Bool( !r.IsEof() && r.GetError() == SVSTREAM_OK ); 84 } 85 86 // Open Record 87 sal_uIntPtr SbiOpenRecord( SvStream& r, sal_uInt16 nSignature, sal_uInt16 nElem ) 88 { 89 sal_uIntPtr nPos = r.Tell(); 90 r << nSignature << (sal_Int32) 0 << nElem; 91 return nPos; 92 } 93 94 // Close Record 95 void SbiCloseRecord( SvStream& r, sal_uIntPtr nOff ) 96 { 97 sal_uIntPtr nPos = r.Tell(); 98 r.Seek( nOff + 2 ); 99 r << (sal_Int32) ( nPos - nOff - 8 ); 100 r.Seek( nPos ); 101 } 102 103 /************************************************************************** 104 * 105 * Load/Store 106 * 107 **************************************************************************/ 108 109 // If the version number does not find, binary parts are omitted, but not 110 // source, comments and name 111 sal_Bool SbiImage::Load( SvStream& r ) 112 { 113 sal_uInt32 nVersion = 0; // Versionsnumber 114 return Load( r, nVersion ); 115 } 116 sal_Bool SbiImage::Load( SvStream& r, sal_uInt32& nVersion ) 117 { 118 119 sal_uInt16 nSign, nCount; 120 sal_uInt32 nLen, nOff; 121 122 Clear(); 123 // Read Master-Record 124 r >> nSign >> nLen >> nCount; 125 sal_uIntPtr nLast = r.Tell() + nLen; 126 sal_uInt32 nCharSet; // System charset 127 sal_uInt32 lDimBase; 128 sal_uInt16 nReserved1; 129 sal_uInt32 nReserved2; 130 sal_uInt32 nReserved3; 131 sal_Bool bBadVer = sal_False; 132 if( nSign == B_MODULE ) 133 { 134 r >> nVersion >> nCharSet >> lDimBase 135 >> nFlags >> nReserved1 >> nReserved2 >> nReserved3; 136 eCharSet = (CharSet) nCharSet; 137 eCharSet = GetSOLoadTextEncoding( eCharSet ); 138 bBadVer = sal_Bool( nVersion > B_CURVERSION ); 139 nDimBase = (sal_uInt16) lDimBase; 140 } 141 142 bool bLegacy = ( nVersion < B_EXT_IMG_VERSION ); 143 144 sal_uIntPtr nNext; 145 while( ( nNext = r.Tell() ) < nLast ) 146 { 147 short i; 148 149 r >> nSign >> nLen >> nCount; 150 nNext += nLen + 8; 151 if( r.GetError() == SVSTREAM_OK ) 152 switch( nSign ) 153 { 154 case B_NAME: 155 r.ReadByteString( aName, eCharSet ); 156 //r >> aName; 157 break; 158 case B_COMMENT: 159 r.ReadByteString( aComment, eCharSet ); 160 //r >> aComment; 161 break; 162 case B_SOURCE: 163 { 164 String aTmp; 165 r.ReadByteString( aTmp, eCharSet ); 166 aOUSource = aTmp; 167 //r >> aSource; 168 break; 169 } 170 #ifdef EXTENDED_BINARY_MODULES 171 case B_EXTSOURCE: 172 { 173 for( sal_uInt16 j = 0 ; j < nCount ; j++ ) 174 { 175 String aTmp; 176 r.ReadByteString( aTmp, eCharSet ); 177 aOUSource += aTmp; 178 } 179 break; 180 } 181 #endif 182 case B_PCODE: 183 if( bBadVer ) break; 184 pCode = new char[ nLen ]; 185 nCodeSize = nLen; 186 r.Read( pCode, nCodeSize ); 187 if ( bLegacy ) 188 { 189 ReleaseLegacyBuffer(); // release any previously held buffer 190 nLegacyCodeSize = (sal_uInt16) nCodeSize; 191 pLegacyPCode = pCode; 192 193 PCodeBuffConvertor< sal_uInt16, sal_uInt32 > aLegacyToNew( (sal_uInt8*)pLegacyPCode, nLegacyCodeSize ); 194 aLegacyToNew.convert(); 195 pCode = (char*)aLegacyToNew.GetBuffer(); 196 nCodeSize = aLegacyToNew.GetSize(); 197 // we don't release the legacy buffer 198 // right now, thats because the module 199 // needs it to fix up the method 200 // nStart members. When that is done 201 // the module can release the buffer 202 // or it can wait until this routine 203 // is called again or when this class // destructs all of which will trigger 204 // release of the buffer. 205 } 206 break; 207 case B_PUBLICS: 208 case B_POOLDIR: 209 case B_SYMPOOL: 210 case B_LINERANGES: 211 break; 212 case B_STRINGPOOL: 213 if( bBadVer ) break; 214 MakeStrings( nCount ); 215 for( i = 0; i < nStrings && SbiGood( r ); i++ ) 216 { 217 r >> nOff; 218 pStringOff[ i ] = (sal_uInt16) nOff; 219 } 220 r >> nLen; 221 if( SbiGood( r ) ) 222 { 223 delete [] pStrings; 224 pStrings = new sal_Unicode[ nLen ]; 225 nStringSize = (sal_uInt16) nLen; 226 227 char* pByteStrings = new char[ nLen ]; 228 r.Read( pByteStrings, nStringSize ); 229 for( short j = 0; j < nStrings; j++ ) 230 { 231 sal_uInt16 nOff2 = (sal_uInt16) pStringOff[ j ]; 232 String aStr( pByteStrings + nOff2, eCharSet ); 233 memcpy( pStrings + nOff2, aStr.GetBuffer(), (aStr.Len() + 1) * sizeof( sal_Unicode ) ); 234 } 235 delete[] pByteStrings; 236 } break; 237 case B_MODEND: 238 goto done; 239 default: 240 break; 241 } 242 else 243 break; 244 r.Seek( nNext ); 245 } 246 done: 247 r.Seek( nLast ); 248 //if( eCharSet != ::GetSystemCharSet() ) 249 //ConvertStrings(); 250 if( !SbiGood( r ) ) 251 bError = sal_True; 252 return sal_Bool( !bError ); 253 } 254 255 sal_Bool SbiImage::Save( SvStream& r, sal_uInt32 nVer ) 256 { 257 bool bLegacy = ( nVer < B_EXT_IMG_VERSION ); 258 259 // detect if old code exceeds legacy limits 260 // if so, then disallow save 261 if ( bLegacy && ExceedsLegacyLimits() ) 262 { 263 SbiImage aEmptyImg; 264 aEmptyImg.aName = aName; 265 aEmptyImg.Save( r, B_LEGACYVERSION ); 266 return sal_True; 267 } 268 // First of all the header 269 sal_uIntPtr nStart = SbiOpenRecord( r, B_MODULE, 1 ); 270 sal_uIntPtr nPos; 271 272 eCharSet = GetSOStoreTextEncoding( eCharSet ); 273 if ( bLegacy ) 274 r << (sal_Int32) B_LEGACYVERSION; 275 else 276 r << (sal_Int32) B_CURVERSION; 277 r << (sal_Int32) eCharSet 278 << (sal_Int32) nDimBase 279 << (sal_Int16) nFlags 280 << (sal_Int16) 0 281 << (sal_Int32) 0 282 << (sal_Int32) 0; 283 284 // Name? 285 if( aName.Len() && SbiGood( r ) ) 286 { 287 nPos = SbiOpenRecord( r, B_NAME, 1 ); 288 r.WriteByteString( aName, eCharSet ); 289 //r << aName; 290 SbiCloseRecord( r, nPos ); 291 } 292 // Comment? 293 if( aComment.Len() && SbiGood( r ) ) 294 { 295 nPos = SbiOpenRecord( r, B_COMMENT, 1 ); 296 r.WriteByteString( aComment, eCharSet ); 297 //r << aComment; 298 SbiCloseRecord( r, nPos ); 299 } 300 // Source? 301 if( aOUSource.getLength() && SbiGood( r ) ) 302 { 303 nPos = SbiOpenRecord( r, B_SOURCE, 1 ); 304 String aTmp; 305 sal_Int32 nLen = aOUSource.getLength(); 306 const sal_Int32 nMaxUnitSize = STRING_MAXLEN - 1; 307 if( nLen > STRING_MAXLEN ) 308 aTmp = aOUSource.copy( 0, nMaxUnitSize ); 309 else 310 aTmp = aOUSource; 311 r.WriteByteString( aTmp, eCharSet ); 312 //r << aSource; 313 SbiCloseRecord( r, nPos ); 314 315 #ifdef EXTENDED_BINARY_MODULES 316 if( nLen > STRING_MAXLEN ) 317 { 318 sal_Int32 nRemainingLen = nLen - nMaxUnitSize; 319 sal_uInt16 nUnitCount = sal_uInt16( (nRemainingLen + nMaxUnitSize - 1) / nMaxUnitSize ); 320 nPos = SbiOpenRecord( r, B_EXTSOURCE, nUnitCount ); 321 for( sal_uInt16 i = 0 ; i < nUnitCount ; i++ ) 322 { 323 sal_Int32 nCopyLen = 324 (nRemainingLen > nMaxUnitSize) ? nMaxUnitSize : nRemainingLen; 325 String aTmp2 = aOUSource.copy( (i+1) * nMaxUnitSize, nCopyLen ); 326 nRemainingLen -= nCopyLen; 327 r.WriteByteString( aTmp2, eCharSet ); 328 } 329 SbiCloseRecord( r, nPos ); 330 } 331 #endif 332 } 333 // Binary data? 334 if( pCode && SbiGood( r ) ) 335 { 336 nPos = SbiOpenRecord( r, B_PCODE, 1 ); 337 if ( bLegacy ) 338 { 339 ReleaseLegacyBuffer(); // release any previously held buffer 340 PCodeBuffConvertor< sal_uInt32, sal_uInt16 > aNewToLegacy( (sal_uInt8*)pCode, nCodeSize ); 341 aNewToLegacy.convert(); 342 pLegacyPCode = (char*)aNewToLegacy.GetBuffer(); 343 nLegacyCodeSize = aNewToLegacy.GetSize(); 344 r.Write( pLegacyPCode, nLegacyCodeSize ); 345 } 346 else 347 r.Write( pCode, nCodeSize ); 348 SbiCloseRecord( r, nPos ); 349 } 350 // String-Pool? 351 if( nStrings ) 352 { 353 nPos = SbiOpenRecord( r, B_STRINGPOOL, nStrings ); 354 // For every String: 355 // sal_uInt32 Offset of the Strings in the Stringblock 356 short i; 357 358 for( i = 0; i < nStrings && SbiGood( r ); i++ ) 359 r << (sal_uInt32) pStringOff[ i ]; 360 361 // Then the String-Block 362 char* pByteStrings = new char[ nStringSize ]; 363 for( i = 0; i < nStrings; i++ ) 364 { 365 sal_uInt16 nOff = (sal_uInt16) pStringOff[ i ]; 366 ByteString aStr( pStrings + nOff, eCharSet ); 367 memcpy( pByteStrings + nOff, aStr.GetBuffer(), (aStr.Len() + 1) * sizeof( char ) ); 368 } 369 r << (sal_uInt32) nStringSize; 370 r.Write( pByteStrings, nStringSize ); 371 372 delete[] pByteStrings; 373 SbiCloseRecord( r, nPos ); 374 } 375 // Set overall length 376 SbiCloseRecord( r, nStart ); 377 if( !SbiGood( r ) ) 378 bError = sal_True; 379 return sal_Bool( !bError ); 380 } 381 382 /************************************************************************** 383 * 384 * Routines called by the compiler 385 * 386 **************************************************************************/ 387 388 void SbiImage::MakeStrings( short nSize ) 389 { 390 nStrings = 0; 391 nStringIdx = 0; 392 nStringOff = 0; 393 nStringSize = 1024; 394 pStrings = new sal_Unicode[ nStringSize ]; 395 pStringOff = new sal_uInt32[ nSize ]; 396 if( pStrings && pStringOff ) 397 { 398 nStrings = nSize; 399 memset( pStringOff, 0, nSize * sizeof( sal_uInt32 ) ); 400 memset( pStrings, 0, nStringSize * sizeof( sal_Unicode ) ); 401 } 402 else 403 bError = sal_True; 404 } 405 406 // Hinzufuegen eines Strings an den StringPool. Der String-Puffer 407 // waechst dynamisch in 1K-Schritten 408 // Add a string to StringPool. The String buffer is dynamically 409 // growing in 1K-Steps 410 void SbiImage::AddString( const String& r ) 411 { 412 if( nStringIdx >= nStrings ) 413 bError = sal_True; 414 if( !bError ) 415 { 416 xub_StrLen len = r.Len() + 1; 417 sal_uInt32 needed = nStringOff + len; 418 if( needed > 0xFFFFFF00L ) 419 bError = sal_True; // out of mem! 420 else if( needed > nStringSize ) 421 { 422 sal_uInt32 nNewLen = needed + 1024; 423 nNewLen &= 0xFFFFFC00; // trim to 1K border 424 if( nNewLen > 0xFFFFFF00L ) 425 nNewLen = 0xFFFFFF00L; 426 sal_Unicode* p = NULL; 427 if( (p = new sal_Unicode[ nNewLen ]) != NULL ) 428 { 429 memcpy( p, pStrings, nStringSize * sizeof( sal_Unicode ) ); 430 delete[] pStrings; 431 pStrings = p; 432 nStringSize = sal::static_int_cast< sal_uInt16 >(nNewLen); 433 } 434 else 435 bError = sal_True; 436 } 437 if( !bError ) 438 { 439 pStringOff[ nStringIdx++ ] = nStringOff; 440 //ByteString aByteStr( r, eCharSet ); 441 memcpy( pStrings + nStringOff, r.GetBuffer(), len * sizeof( sal_Unicode ) ); 442 nStringOff = nStringOff + len; 443 // Last String? The update the size of the buffer 444 if( nStringIdx >= nStrings ) 445 nStringSize = nStringOff; 446 } 447 } 448 } 449 450 // Add code block 451 // The block was fetched by the compiler from class SbBuffer and 452 // is already created with new. Additionally it contains all Integers 453 // in Big Endian format, so can be directly read/written. 454 void SbiImage::AddCode( char* p, sal_uInt32 s ) 455 { 456 pCode = p; 457 nCodeSize = s; 458 } 459 460 // Add user type 461 void SbiImage::AddType(SbxObject* pObject) 462 { 463 if( !rTypes.Is() ) 464 rTypes = new SbxArray; 465 SbxObject *pCopyObject = new SbxObject(*pObject); 466 rTypes->Insert (pCopyObject,rTypes->Count()); 467 } 468 469 void SbiImage::AddEnum(SbxObject* pObject) // Register enum type 470 { 471 if( !rEnums.Is() ) 472 rEnums = new SbxArray; 473 rEnums->Insert( pObject, rEnums->Count() ); 474 } 475 476 477 /************************************************************************** 478 * 479 * Accessing the image 480 * 481 **************************************************************************/ 482 483 // Note: IDs start with 1 484 String SbiImage::GetString( short nId ) const 485 { 486 if( nId && nId <= nStrings ) 487 { 488 sal_uInt32 nOff = pStringOff[ nId - 1 ]; 489 sal_Unicode* pStr = pStrings + nOff; 490 491 // #i42467: Special treatment for vbNullChar 492 if( *pStr == 0 ) 493 { 494 sal_uInt32 nNextOff = (nId < nStrings) ? pStringOff[ nId ] : nStringOff; 495 sal_uInt32 nLen = nNextOff - nOff - 1; 496 if( nLen == 1 ) 497 { 498 // Force length 1 and make char 0 afterwards 499 String aNullCharStr( String::CreateFromAscii( " " ) ); 500 aNullCharStr.SetChar( 0, 0 ); 501 return aNullCharStr; 502 } 503 } 504 else 505 { 506 String aStr( pStr ); 507 return aStr; 508 } 509 } 510 return String(); 511 } 512 513 const SbxObject* SbiImage::FindType (String aTypeName) const 514 { 515 return rTypes.Is() ? (SbxObject*)rTypes->Find(aTypeName,SbxCLASS_OBJECT) : NULL; 516 } 517 518 sal_uInt16 SbiImage::CalcLegacyOffset( sal_Int32 nOffset ) 519 { 520 return SbiCodeGen::calcLegacyOffSet( (sal_uInt8*)pCode, nOffset ) ; 521 } 522 523 sal_uInt32 SbiImage::CalcNewOffset( sal_Int16 nOffset ) 524 { 525 return SbiCodeGen::calcNewOffSet( (sal_uInt8*)pLegacyPCode, nOffset ) ; 526 } 527 528 void SbiImage::ReleaseLegacyBuffer() 529 { 530 delete[] pLegacyPCode; 531 pLegacyPCode = NULL; 532 nLegacyCodeSize = 0; 533 } 534 535 sal_Bool SbiImage::ExceedsLegacyLimits() 536 { 537 if ( ( nStringSize > 0xFF00L ) || ( CalcLegacyOffset( nCodeSize ) > 0xFF00L ) ) 538 return sal_True; 539 return sal_False; 540 } 541