1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <tools/stream.hxx> 21 #include <tools/tenccvt.hxx> 22 #include <osl/thread.h> 23 #include <sal/log.hxx> 24 #include <basic/sbx.hxx> 25 #include <sb.hxx> 26 #include <string.h> 27 #include <image.hxx> 28 #include <codegen.hxx> 29 #include <memory> 30 31 SbiImage::SbiImage() 32 { 33 pStrings = nullptr; 34 pCode = nullptr; 35 pLegacyPCode = nullptr; 36 nFlags = SbiImageFlags::NONE; 37 nStringSize= 0; 38 nCodeSize = 0; 39 nLegacyCodeSize = 40 nDimBase = 0; 41 bInit = 42 bError = false; 43 bFirstInit = true; 44 eCharSet = osl_getThreadTextEncoding(); 45 nStringIdx = 0; 46 nStringOff = 0; 47 } 48 49 SbiImage::~SbiImage() 50 { 51 Clear(); 52 } 53 54 void SbiImage::Clear() 55 { 56 mvStringOffsets.clear(); 57 pStrings.reset(); 58 pCode.reset(); 59 pLegacyPCode.reset(); 60 pStrings = nullptr; 61 pCode = nullptr; 62 nFlags = SbiImageFlags::NONE; 63 nStringSize= 0; 64 nLegacyCodeSize = 0; 65 nCodeSize = 0; 66 eCharSet = osl_getThreadTextEncoding(); 67 nDimBase = 0; 68 bError = false; 69 } 70 71 static bool SbiGood( SvStream const & r ) 72 { 73 return r.good(); 74 } 75 76 // Open Record 77 static sal_uInt64 SbiOpenRecord( SvStream& r, FileOffset nSignature, sal_uInt16 nElem ) 78 { 79 sal_uInt64 nPos = r.Tell(); 80 r.WriteUInt16( static_cast<sal_uInt16>( nSignature ) ) 81 .WriteInt32( 0 ).WriteUInt16( nElem ); 82 return nPos; 83 } 84 85 // Close Record 86 static void SbiCloseRecord( SvStream& r, sal_uInt64 nOff ) 87 { 88 sal_uInt64 nPos = r.Tell(); 89 r.Seek( nOff + 2 ); 90 r.WriteInt32(nPos - nOff - 8 ); 91 r.Seek( nPos ); 92 } 93 94 bool SbiImage::Load( SvStream& r, sal_uInt32& nVersion ) 95 { 96 97 sal_uInt16 nSign, nCount; 98 sal_uInt32 nLen, nOff; 99 100 Clear(); 101 // Read Master-Record 102 r.ReadUInt16( nSign ).ReadUInt32( nLen ).ReadUInt16( nCount ); 103 sal_uInt64 nLast = r.Tell() + nLen; 104 sal_uInt32 nCharSet; // System charset 105 sal_uInt32 lDimBase; 106 sal_uInt16 nReserved1; 107 sal_uInt32 nReserved2; 108 sal_uInt32 nReserved3; 109 bool bBadVer = false; 110 if( nSign == static_cast<sal_uInt16>( FileOffset::Module ) ) 111 { 112 sal_uInt16 nTmpFlags; 113 r.ReadUInt32( nVersion ).ReadUInt32( nCharSet ).ReadUInt32( lDimBase ) 114 .ReadUInt16( nTmpFlags ).ReadUInt16( nReserved1 ).ReadUInt32( nReserved2 ).ReadUInt32( nReserved3 ); 115 nFlags = static_cast<SbiImageFlags>(nTmpFlags); 116 eCharSet = nCharSet; 117 eCharSet = GetSOLoadTextEncoding( eCharSet ); 118 bBadVer = ( nVersion > B_CURVERSION ); 119 nDimBase = static_cast<sal_uInt16>(lDimBase); 120 } 121 122 bool bLegacy = ( nVersion < B_EXT_IMG_VERSION ); 123 124 sal_uInt64 nNext; 125 while( ( nNext = r.Tell() ) < nLast ) 126 { 127 128 r.ReadUInt16( nSign ).ReadUInt32( nLen ).ReadUInt16( nCount ); 129 nNext += nLen + 8; 130 if( r.GetError() == ERRCODE_NONE ) 131 { 132 switch( static_cast<FileOffset>( nSign ) ) 133 { 134 case FileOffset::Name: 135 aName = r.ReadUniOrByteString(eCharSet); 136 break; 137 case FileOffset::Comment: 138 aComment = r.ReadUniOrByteString(eCharSet ); 139 break; 140 case FileOffset::Source: 141 { 142 aOUSource = r.ReadUniOrByteString(eCharSet); 143 break; 144 } 145 case FileOffset::ExtSource: 146 { 147 //assuming an empty string with just the lead 32bit/16bit len indicator 148 const size_t nMinStringSize = (eCharSet == RTL_TEXTENCODING_UNICODE) ? 4 : 2; 149 const sal_uInt64 nMaxStrings = r.remainingSize() / nMinStringSize; 150 if (nCount > nMaxStrings) 151 { 152 SAL_WARN("basic", "Parsing error: " << nMaxStrings << 153 " max possible entries, but " << nCount << " claimed, truncating"); 154 nCount = nMaxStrings; 155 } 156 for( sal_uInt16 j = 0; j < nCount; ++j) 157 { 158 aOUSource += r.ReadUniOrByteString(eCharSet); 159 } 160 break; 161 } 162 case FileOffset::PCode: 163 if( bBadVer ) break; 164 pCode.reset(new char[ nLen ]); 165 nCodeSize = nLen; 166 r.ReadBytes(pCode.get(), nCodeSize); 167 if ( bLegacy ) 168 { 169 nLegacyCodeSize = static_cast<sal_uInt16>(nCodeSize); 170 pLegacyPCode = std::move(pCode); 171 172 PCodeBuffConvertor< sal_uInt16, sal_uInt32 > aLegacyToNew( reinterpret_cast<sal_uInt8*>(pLegacyPCode.get()), nLegacyCodeSize ); 173 aLegacyToNew.convert(); 174 pCode.reset(reinterpret_cast<char*>(aLegacyToNew.GetBuffer())); 175 nCodeSize = aLegacyToNew.GetSize(); 176 // we don't release the legacy buffer 177 // right now, that's because the module 178 // needs it to fix up the method 179 // nStart members. When that is done 180 // the module can release the buffer 181 // or it can wait until this routine 182 // is called again or when this class // destructs all of which will trigger 183 // release of the buffer. 184 } 185 break; 186 case FileOffset::Publics: 187 case FileOffset::PoolDir: 188 case FileOffset::SymPool: 189 case FileOffset::LineRanges: 190 break; 191 case FileOffset::StringPool: 192 { 193 if( bBadVer ) break; 194 //assuming an empty string with just the lead 32bit len indicator 195 const sal_uInt64 nMinStringSize = 4; 196 const sal_uInt64 nMaxStrings = r.remainingSize() / nMinStringSize; 197 if (nCount > nMaxStrings) 198 { 199 SAL_WARN("basic", "Parsing error: " << nMaxStrings << 200 " max possible entries, but " << nCount << " claimed, truncating"); 201 nCount = nMaxStrings; 202 } 203 MakeStrings( nCount ); 204 for( size_t i = 0; i < mvStringOffsets.size() && SbiGood( r ); i++ ) 205 { 206 r.ReadUInt32( nOff ); 207 mvStringOffsets[ i ] = static_cast<sal_uInt16>(nOff); 208 } 209 r.ReadUInt32( nLen ); 210 if( SbiGood( r ) ) 211 { 212 pStrings.reset(new sal_Unicode[ nLen ]); 213 nStringSize = static_cast<sal_uInt16>(nLen); 214 215 std::unique_ptr<char[]> pByteStrings(new char[ nLen ]); 216 r.ReadBytes(pByteStrings.get(), nStringSize); 217 for( size_t j = 0; j < mvStringOffsets.size(); j++ ) 218 { 219 sal_uInt16 nOff2 = static_cast<sal_uInt16>(mvStringOffsets[ j ]); 220 OUString aStr( pByteStrings.get() + nOff2, strlen(pByteStrings.get() + nOff2), eCharSet ); 221 memcpy( pStrings.get() + nOff2, aStr.getStr(), (aStr.getLength() + 1) * sizeof( sal_Unicode ) ); 222 } 223 } 224 break; 225 } 226 case FileOffset::UserTypes: 227 { 228 //assuming an empty string with just the lead 32bit/16bit len indicator 229 const size_t nMinStringSize = (eCharSet == RTL_TEXTENCODING_UNICODE) ? 4 : 2; 230 const sal_uInt64 nMinRecordSize = nMinStringSize + sizeof(sal_Int16); 231 const sal_uInt64 nMaxRecords = r.remainingSize() / nMinRecordSize; 232 if (nCount > nMaxRecords) 233 { 234 SAL_WARN("basic", "Parsing error: " << nMaxRecords << 235 " max possible entries, but " << nCount << " claimed, truncating"); 236 nCount = nMaxRecords; 237 } 238 239 // User defined types 240 for (sal_uInt16 i = 0; i < nCount; i++) 241 { 242 OUString aTypeName = r.ReadUniOrByteString(eCharSet); 243 244 sal_uInt16 nTypeMembers; 245 r.ReadUInt16(nTypeMembers); 246 247 const sal_uInt64 nMaxTypeMembers = r.remainingSize() / 8; 248 if (nTypeMembers > nMaxTypeMembers) 249 { 250 SAL_WARN("basic", "Parsing error: " << nMaxTypeMembers << 251 " max possible entries, but " << nTypeMembers << " claimed, truncating"); 252 nTypeMembers = nMaxTypeMembers; 253 } 254 255 SbxObject *pType = new SbxObject(aTypeName); 256 SbxArray *pTypeMembers = pType->GetProperties(); 257 258 for (sal_uInt16 j = 0; j < nTypeMembers; j++) 259 { 260 OUString aMemberName = r.ReadUniOrByteString(eCharSet); 261 262 sal_Int16 aIntMemberType; 263 r.ReadInt16(aIntMemberType); 264 SbxDataType aMemberType = static_cast< SbxDataType > ( aIntMemberType ); 265 266 SbxProperty *pTypeElem = new SbxProperty( aMemberName, aMemberType ); 267 268 sal_uInt32 aIntFlag; 269 r.ReadUInt32(aIntFlag); 270 SbxFlagBits nElemFlags = static_cast< SbxFlagBits > ( aIntFlag ); 271 272 pTypeElem->SetFlags(nElemFlags); 273 274 sal_Int16 hasObject; 275 r.ReadInt16(hasObject); 276 277 if (hasObject == 1) 278 { 279 if(aMemberType == SbxOBJECT) 280 { 281 // nested user defined types 282 // declared before use, so it is ok to reference it by name on load 283 OUString aNestedTypeName = r.ReadUniOrByteString(eCharSet); 284 SbxObject* pNestedTypeObj = static_cast< SbxObject* >( rTypes->Find( aNestedTypeName, SbxClassType::Object ) ); 285 if (pNestedTypeObj) 286 { 287 SbxObject* pCloneObj = cloneTypeObjectImpl( *pNestedTypeObj ); 288 pTypeElem->PutObject( pCloneObj ); 289 } 290 } 291 else 292 { 293 // an array 294 SbxDimArray* pArray = new SbxDimArray(); 295 296 sal_Int16 isFixedSize; 297 r.ReadInt16(isFixedSize); 298 if (isFixedSize == 1) 299 pArray->setHasFixedSize( true ); 300 301 sal_Int32 nDims; 302 r.ReadInt32(nDims); 303 for (sal_Int32 d = 0; d < nDims; d++) 304 { 305 sal_Int32 lBound; 306 sal_Int32 uBound; 307 r.ReadInt32(lBound).ReadInt32(uBound); 308 pArray->unoAddDim32(lBound, uBound); 309 } 310 311 pTypeElem->PutObject( pArray ); 312 } 313 } 314 315 pTypeMembers->Insert( pTypeElem, pTypeMembers->Count() ); 316 317 } 318 319 pType->Remove( "Name", SbxClassType::DontCare ); 320 pType->Remove( "Parent", SbxClassType::DontCare ); 321 322 AddType(pType); 323 } 324 break; 325 } 326 case FileOffset::ModEnd: 327 goto done; 328 default: 329 break; 330 } 331 } 332 else 333 { 334 break; 335 } 336 r.Seek( nNext ); 337 } 338 done: 339 r.Seek( nLast ); 340 if( !SbiGood( r ) ) 341 { 342 bError = true; 343 } 344 return !bError; 345 } 346 347 bool SbiImage::Save( SvStream& r, sal_uInt32 nVer ) 348 { 349 bool bLegacy = ( nVer < B_EXT_IMG_VERSION ); 350 351 // detect if old code exceeds legacy limits 352 // if so, then disallow save 353 if ( bLegacy && ExceedsLegacyLimits() ) 354 { 355 SbiImage aEmptyImg; 356 aEmptyImg.aName = aName; 357 aEmptyImg.Save( r, B_LEGACYVERSION ); 358 return true; 359 } 360 // First of all the header 361 sal_uInt64 nStart = SbiOpenRecord( r, FileOffset::Module, 1 ); 362 sal_uInt64 nPos; 363 364 eCharSet = GetSOStoreTextEncoding( eCharSet ); 365 if ( bLegacy ) 366 { 367 r.WriteInt32( B_LEGACYVERSION ); 368 } 369 else 370 { 371 r.WriteInt32( B_CURVERSION ); 372 } 373 r .WriteInt32( eCharSet ) 374 .WriteInt32( nDimBase ) 375 .WriteInt16( static_cast<sal_uInt16>(nFlags) ) 376 .WriteInt16( 0 ) 377 .WriteInt32( 0 ) 378 .WriteInt32( 0 ); 379 380 // Name? 381 if( !aName.isEmpty() && SbiGood( r ) ) 382 { 383 nPos = SbiOpenRecord( r, FileOffset::Name, 1 ); 384 r.WriteUniOrByteString( aName, eCharSet ); 385 SbiCloseRecord( r, nPos ); 386 } 387 // Comment? 388 if( !aComment.isEmpty() && SbiGood( r ) ) 389 { 390 nPos = SbiOpenRecord( r, FileOffset::Comment, 1 ); 391 r.WriteUniOrByteString( aComment, eCharSet ); 392 SbiCloseRecord( r, nPos ); 393 } 394 // Source? 395 if( !aOUSource.isEmpty() && SbiGood( r ) ) 396 { 397 nPos = SbiOpenRecord( r, FileOffset::Source, 1 ); 398 r.WriteUniOrByteString( aOUSource, eCharSet ); 399 SbiCloseRecord( r, nPos ); 400 } 401 // Binary data? 402 if( pCode && SbiGood( r ) ) 403 { 404 nPos = SbiOpenRecord( r, FileOffset::PCode, 1 ); 405 if ( bLegacy ) 406 { 407 PCodeBuffConvertor< sal_uInt32, sal_uInt16 > aNewToLegacy( reinterpret_cast<sal_uInt8*>(pCode.get()), nCodeSize ); 408 aNewToLegacy.convert(); 409 pLegacyPCode.reset(reinterpret_cast<char*>(aNewToLegacy.GetBuffer())); 410 nLegacyCodeSize = aNewToLegacy.GetSize(); 411 r.WriteBytes(pLegacyPCode.get(), nLegacyCodeSize); 412 } 413 else 414 { 415 r.WriteBytes(pCode.get(), nCodeSize); 416 } 417 SbiCloseRecord( r, nPos ); 418 } 419 // String-Pool? 420 if( !mvStringOffsets.empty() ) 421 { 422 nPos = SbiOpenRecord( r, FileOffset::StringPool, mvStringOffsets.size() ); 423 // For every String: 424 // sal_uInt32 Offset of the Strings in the Stringblock 425 for( size_t i = 0; i < mvStringOffsets.size() && SbiGood( r ); i++ ) 426 { 427 r.WriteUInt32( mvStringOffsets[ i ] ); 428 } 429 // Then the String-Block 430 std::unique_ptr<char[]> pByteStrings(new char[ nStringSize ]); 431 for( size_t i = 0; i < mvStringOffsets.size(); i++ ) 432 { 433 sal_uInt16 nOff = static_cast<sal_uInt16>(mvStringOffsets[ i ]); 434 OString aStr(OUStringToOString(OUString(pStrings.get() + nOff), eCharSet)); 435 memcpy( pByteStrings.get() + nOff, aStr.getStr(), (aStr.getLength() + 1) * sizeof( char ) ); 436 } 437 r.WriteUInt32( nStringSize ); 438 r.WriteBytes(pByteStrings.get(), nStringSize); 439 440 pByteStrings.reset(); 441 SbiCloseRecord( r, nPos ); 442 } 443 // User defined types 444 if ( rTypes.is() ) 445 { 446 sal_uInt16 nTypes = rTypes->Count(); 447 if (nTypes > 0 ) 448 { 449 nPos = SbiOpenRecord( r, FileOffset::UserTypes, nTypes ); 450 451 for (sal_uInt16 i = 0; i < nTypes; i++) 452 { 453 SbxObject* pType = static_cast< SbxObject* > ( rTypes->Get(i) ); 454 OUString aTypeName = pType->GetClassName(); 455 456 r.WriteUniOrByteString( aTypeName, eCharSet ); 457 458 SbxArray *pTypeMembers = pType->GetProperties(); 459 sal_uInt16 nTypeMembers = pTypeMembers->Count(); 460 461 r.WriteInt16(nTypeMembers); 462 463 for (sal_uInt16 j = 0; j < nTypeMembers; j++) 464 { 465 466 SbxProperty* pTypeElem = static_cast< SbxProperty* > ( pTypeMembers->Get(j) ); 467 468 const OUString& aElemName = pTypeElem->GetName(); 469 r.WriteUniOrByteString( aElemName, eCharSet ); 470 471 SbxDataType dataType = pTypeElem->GetType(); 472 r.WriteInt16(dataType); 473 474 SbxFlagBits nElemFlags = pTypeElem->GetFlags(); 475 r.WriteUInt32(static_cast< sal_uInt32 > (nElemFlags) ); 476 477 SbxBase* pElemObject = pTypeElem->GetObject(); 478 479 if (pElemObject) 480 { 481 r.WriteInt16(1); // has elem Object 482 483 if( dataType == SbxOBJECT ) 484 { 485 // nested user defined types 486 // declared before use, so it is ok to reference it by name on load 487 SbxObject* pNestedType = static_cast< SbxObject* > ( pElemObject ); 488 r.WriteUniOrByteString( pNestedType->GetClassName(), eCharSet ); 489 } 490 else 491 { 492 // an array 493 SbxDimArray* pArray = static_cast< SbxDimArray* > ( pElemObject ); 494 495 bool bFixedSize = pArray->hasFixedSize(); 496 if (bFixedSize) 497 r.WriteInt16(1); 498 else 499 r.WriteInt16(0); 500 501 sal_Int32 nDims = pArray->GetDims(); 502 r.WriteInt32(nDims); 503 504 for (sal_Int32 d = 0; d < nDims; d++) 505 { 506 sal_Int32 lBound; 507 sal_Int32 uBound; 508 pArray->GetDim32(d, lBound, uBound); 509 r.WriteInt32(lBound).WriteInt32(uBound); 510 } 511 } 512 } 513 else 514 r.WriteInt16(0); // no elem Object 515 516 } 517 } 518 SbiCloseRecord( r, nPos ); 519 } 520 } 521 // Set overall length 522 SbiCloseRecord( r, nStart ); 523 if( !SbiGood( r ) ) 524 { 525 bError = true; 526 } 527 return !bError; 528 } 529 530 void SbiImage::MakeStrings( short nSize ) 531 { 532 nStringIdx = 0; 533 nStringOff = 0; 534 nStringSize = 1024; 535 pStrings.reset( new sal_Unicode[ nStringSize ]); 536 mvStringOffsets.resize(nSize); 537 if (nSize != 0) { 538 memset( mvStringOffsets.data(), 0, nSize * sizeof( sal_uInt32 ) ); 539 } 540 memset( pStrings.get(), 0, nStringSize * sizeof( sal_Unicode ) ); 541 } 542 543 // Add a string to StringPool. The String buffer is dynamically 544 // growing in 1K-Steps 545 void SbiImage::AddString( const OUString& r ) 546 { 547 if( nStringIdx >= short(mvStringOffsets.size()) ) 548 { 549 bError = true; 550 } 551 if( !bError ) 552 { 553 sal_Int32 len = r.getLength() + 1; 554 sal_uInt32 needed = nStringOff + len; 555 if( needed > 0xFFFFFF00 ) 556 { 557 bError = true; // out of mem! 558 } 559 else if( needed > nStringSize ) 560 { 561 sal_uInt32 nNewLen = needed + 1024; 562 nNewLen &= 0xFFFFFC00; // trim to 1K border 563 std::unique_ptr<sal_Unicode[]> p(new sal_Unicode[nNewLen]); 564 memcpy( p.get(), pStrings.get(), nStringSize * sizeof( sal_Unicode ) ); 565 pStrings = std::move(p); 566 nStringSize = sal::static_int_cast< sal_uInt16 >(nNewLen); 567 } 568 if( !bError ) 569 { 570 mvStringOffsets[ nStringIdx++ ] = nStringOff; 571 memcpy( pStrings.get() + nStringOff, r.getStr(), len * sizeof( sal_Unicode ) ); 572 nStringOff = nStringOff + len; 573 // Last String? The update the size of the buffer 574 if( nStringIdx >= short(mvStringOffsets.size()) ) 575 { 576 nStringSize = nStringOff; 577 } 578 } 579 } 580 } 581 582 // Add code block 583 // The block was fetched by the compiler from class SbBuffer and 584 // is already created with new. Additionally it contains all Integers 585 // in Big Endian format, so can be directly read/written. 586 void SbiImage::AddCode( std::unique_ptr<char[]> p, sal_uInt32 s ) 587 { 588 pCode = std::move(p); 589 nCodeSize = s; 590 } 591 592 // Add user type 593 void SbiImage::AddType(SbxObject const * pObject) 594 { 595 if( !rTypes.is() ) 596 { 597 rTypes = new SbxArray; 598 } 599 SbxObject *pCopyObject = new SbxObject(*pObject); 600 rTypes->Insert (pCopyObject,rTypes->Count()); 601 } 602 603 void SbiImage::AddEnum(SbxObject* pObject) // Register enum type 604 { 605 if( !rEnums.is() ) 606 { 607 rEnums = new SbxArray; 608 } 609 rEnums->Insert( pObject, rEnums->Count() ); 610 } 611 612 // Note: IDs start with 1 613 OUString SbiImage::GetString( short nId ) const 614 { 615 if( nId && nId <= short(mvStringOffsets.size()) ) 616 { 617 sal_uInt32 nOff = mvStringOffsets[ nId - 1 ]; 618 sal_Unicode* pStr = pStrings.get() + nOff; 619 620 // #i42467: Special treatment for vbNullChar 621 if( *pStr == 0 ) 622 { 623 sal_uInt32 nNextOff = (nId < short(mvStringOffsets.size())) ? mvStringOffsets[ nId ] : nStringOff; 624 sal_uInt32 nLen = nNextOff - nOff - 1; 625 if( nLen == 1 ) 626 { 627 // Force length 1 and make char 0 afterwards 628 OUString aNullCharStr( u'\0'); 629 return aNullCharStr; 630 } 631 } 632 else 633 { 634 return OUString(pStr); 635 } 636 } 637 return OUString(); 638 } 639 640 const SbxObject* SbiImage::FindType (const OUString& aTypeName) const 641 { 642 return rTypes.is() ? static_cast<SbxObject*>(rTypes->Find(aTypeName,SbxClassType::Object)) : nullptr; 643 } 644 645 sal_uInt16 SbiImage::CalcLegacyOffset( sal_Int32 nOffset ) 646 { 647 return SbiCodeGen::calcLegacyOffSet( reinterpret_cast<sal_uInt8*>(pCode.get()), nOffset ) ; 648 } 649 650 sal_uInt32 SbiImage::CalcNewOffset( sal_Int16 nOffset ) 651 { 652 return SbiCodeGen::calcNewOffSet( reinterpret_cast<sal_uInt8*>(pLegacyPCode.get()), nOffset ) ; 653 } 654 655 void SbiImage::ReleaseLegacyBuffer() 656 { 657 pLegacyPCode.reset(); 658 nLegacyCodeSize = 0; 659 } 660 661 bool SbiImage::ExceedsLegacyLimits() 662 { 663 return ( nStringSize > 0xFF00 ) || ( CalcLegacyOffset( nCodeSize ) > 0xFF00 ); 664 } 665 666 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 667
