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