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