update credits
[LibreOffice.git] / basic / source / classes / image.cxx
blob8a4412d1b5c50a645233d88be10ba399ff099eb1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tools/stream.hxx>
21 #include <tools/tenccvt.hxx>
22 #include <basic/sbx.hxx>
23 #include "sb.hxx"
24 #include <string.h> // memset() etc
25 #include "image.hxx"
26 #include <codegen.hxx>
27 SbiImage::SbiImage()
29 pStringOff = NULL;
30 pStrings = NULL;
31 pCode = NULL;
32 pLegacyPCode = NULL;
33 nFlags = 0;
34 nStrings = 0;
35 nStringSize= 0;
36 nCodeSize = 0;
37 nLegacyCodeSize =
38 nDimBase = 0;
39 bInit =
40 bError = false;
41 bFirstInit = true;
42 eCharSet = osl_getThreadTextEncoding();
45 SbiImage::~SbiImage()
47 Clear();
50 void SbiImage::Clear()
52 delete[] pStringOff;
53 delete[] pStrings;
54 delete[] pCode;
55 ReleaseLegacyBuffer();
56 pStringOff = NULL;
57 pStrings = NULL;
58 pCode = NULL;
59 nFlags = 0;
60 nStrings = 0;
61 nStringSize= 0;
62 nLegacyCodeSize = 0;
63 nCodeSize = 0;
64 eCharSet = osl_getThreadTextEncoding();
65 nDimBase = 0;
66 bError = false;
69 /**************************************************************************
71 * Service-Routines for Load/Store
73 **************************************************************************/
75 bool SbiGood( SvStream& r )
77 return !r.IsEof() && r.GetError() == SVSTREAM_OK;
80 // Open Record
81 sal_uIntPtr SbiOpenRecord( SvStream& r, sal_uInt16 nSignature, sal_uInt16 nElem )
83 sal_uIntPtr nPos = r.Tell();
84 r << nSignature << (sal_Int32) 0 << nElem;
85 return nPos;
88 // Close Record
89 void SbiCloseRecord( SvStream& r, sal_uIntPtr nOff )
91 sal_uIntPtr nPos = r.Tell();
92 r.Seek( nOff + 2 );
93 r << (sal_Int32) ( nPos - nOff - 8 );
94 r.Seek( nPos );
97 /**************************************************************************
99 * Load/Store
101 **************************************************************************/
103 bool SbiImage::Load( SvStream& r, sal_uInt32& nVersion )
106 sal_uInt16 nSign, nCount;
107 sal_uInt32 nLen, nOff;
109 Clear();
110 // Read Master-Record
111 r >> nSign >> nLen >> nCount;
112 sal_uIntPtr nLast = r.Tell() + nLen;
113 sal_uInt32 nCharSet; // System charset
114 sal_uInt32 lDimBase;
115 sal_uInt16 nReserved1;
116 sal_uInt32 nReserved2;
117 sal_uInt32 nReserved3;
118 bool bBadVer = false;
119 if( nSign == B_MODULE )
121 r >> nVersion >> nCharSet >> lDimBase
122 >> nFlags >> nReserved1 >> nReserved2 >> nReserved3;
123 eCharSet = (CharSet) nCharSet;
124 eCharSet = GetSOLoadTextEncoding( eCharSet );
125 bBadVer = ( nVersion > B_CURVERSION );
126 nDimBase = (sal_uInt16) lDimBase;
129 bool bLegacy = ( nVersion < B_EXT_IMG_VERSION );
131 sal_uIntPtr nNext;
132 while( ( nNext = r.Tell() ) < nLast )
135 r >> nSign >> nLen >> nCount;
136 nNext += nLen + 8;
137 if( r.GetError() == SVSTREAM_OK )
139 switch( nSign )
141 case B_NAME:
142 aName = r.ReadUniOrByteString(eCharSet);
143 break;
144 case B_COMMENT:
145 aComment = r.ReadUniOrByteString(eCharSet );
146 break;
147 case B_SOURCE:
149 aOUSource = r.ReadUniOrByteString(eCharSet);
150 break;
152 case B_EXTSOURCE:
154 for( sal_uInt16 j = 0 ; j < nCount ; j++ )
156 aOUSource += r.ReadUniOrByteString(eCharSet);
158 break;
160 case B_PCODE:
161 if( bBadVer ) break;
162 pCode = new char[ nLen ];
163 nCodeSize = nLen;
164 r.Read( pCode, nCodeSize );
165 if ( bLegacy )
167 ReleaseLegacyBuffer(); // release any previously held buffer
168 nLegacyCodeSize = (sal_uInt16) nCodeSize;
169 pLegacyPCode = pCode;
171 PCodeBuffConvertor< sal_uInt16, sal_uInt32 > aLegacyToNew( (sal_uInt8*)pLegacyPCode, nLegacyCodeSize );
172 aLegacyToNew.convert();
173 pCode = (char*)aLegacyToNew.GetBuffer();
174 nCodeSize = aLegacyToNew.GetSize();
175 // we don't release the legacy buffer
176 // right now, thats 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.
184 break;
185 case B_PUBLICS:
186 case B_POOLDIR:
187 case B_SYMPOOL:
188 case B_LINERANGES:
189 break;
190 case B_STRINGPOOL:
191 if( bBadVer ) break;
192 MakeStrings( nCount );
193 short i;
194 for( i = 0; i < nStrings && SbiGood( r ); i++ )
196 r >> nOff;
197 pStringOff[ i ] = (sal_uInt16) nOff;
199 r >> nLen;
200 if( SbiGood( r ) )
202 delete [] pStrings;
203 pStrings = new sal_Unicode[ nLen ];
204 nStringSize = (sal_uInt16) nLen;
206 char* pByteStrings = new char[ nLen ];
207 r.Read( pByteStrings, nStringSize );
208 for( short j = 0; j < nStrings; j++ )
210 sal_uInt16 nOff2 = (sal_uInt16) pStringOff[ j ];
211 OUString aStr( pByteStrings + nOff2, strlen(pByteStrings + nOff2), eCharSet );
212 memcpy( pStrings + nOff2, aStr.getStr(), (aStr.getLength() + 1) * sizeof( sal_Unicode ) );
214 delete[] pByteStrings;
216 break;
217 case B_MODEND:
218 goto done;
219 default:
220 break;
223 else
225 break;
227 r.Seek( nNext );
229 done:
230 r.Seek( nLast );
231 if( !SbiGood( r ) )
233 bError = true;
235 return !bError;
238 bool SbiImage::Save( SvStream& r, sal_uInt32 nVer )
240 bool bLegacy = ( nVer < B_EXT_IMG_VERSION );
242 // detect if old code exceeds legacy limits
243 // if so, then disallow save
244 if ( bLegacy && ExceedsLegacyLimits() )
246 SbiImage aEmptyImg;
247 aEmptyImg.aName = aName;
248 aEmptyImg.Save( r, B_LEGACYVERSION );
249 return true;
251 // First of all the header
252 sal_uIntPtr nStart = SbiOpenRecord( r, B_MODULE, 1 );
253 sal_uIntPtr nPos;
255 eCharSet = GetSOStoreTextEncoding( eCharSet );
256 if ( bLegacy )
258 r << (sal_Int32) B_LEGACYVERSION;
260 else
262 r << (sal_Int32) B_CURVERSION;
264 r << (sal_Int32) eCharSet
265 << (sal_Int32) nDimBase
266 << (sal_Int16) nFlags
267 << (sal_Int16) 0
268 << (sal_Int32) 0
269 << (sal_Int32) 0;
271 // Name?
272 if( !aName.isEmpty() && SbiGood( r ) )
274 nPos = SbiOpenRecord( r, B_NAME, 1 );
275 r.WriteUniOrByteString( aName, eCharSet );
276 SbiCloseRecord( r, nPos );
278 // Comment?
279 if( !aComment.isEmpty() && SbiGood( r ) )
281 nPos = SbiOpenRecord( r, B_COMMENT, 1 );
282 r.WriteUniOrByteString( aComment, eCharSet );
283 SbiCloseRecord( r, nPos );
285 // Source?
286 if( !aOUSource.isEmpty() && SbiGood( r ) )
288 nPos = SbiOpenRecord( r, B_SOURCE, 1 );
289 OUString aTmp;
290 sal_Int32 nLen = aOUSource.getLength();
291 const sal_Int32 nMaxUnitSize = STRING_MAXLEN - 1;
292 if( nLen > STRING_MAXLEN )
294 aTmp = aOUSource.copy( 0, nMaxUnitSize );
296 else
298 aTmp = aOUSource;
300 r.WriteUniOrByteString( aTmp, eCharSet );
301 SbiCloseRecord( r, nPos );
303 if( nLen > STRING_MAXLEN )
305 sal_Int32 nRemainingLen = nLen - nMaxUnitSize;
306 sal_uInt16 nUnitCount = sal_uInt16( (nRemainingLen + nMaxUnitSize - 1) / nMaxUnitSize );
307 nPos = SbiOpenRecord( r, B_EXTSOURCE, nUnitCount );
308 for( sal_uInt16 i = 0 ; i < nUnitCount ; i++ )
310 sal_Int32 nCopyLen = (nRemainingLen > nMaxUnitSize) ? nMaxUnitSize : nRemainingLen;
311 OUString aTmp2 = aOUSource.copy( (i+1) * nMaxUnitSize, nCopyLen );
312 nRemainingLen -= nCopyLen;
313 r.WriteUniOrByteString( aTmp2, eCharSet );
315 SbiCloseRecord( r, nPos );
318 // Binary data?
319 if( pCode && SbiGood( r ) )
321 nPos = SbiOpenRecord( r, B_PCODE, 1 );
322 if ( bLegacy )
324 ReleaseLegacyBuffer(); // release any previously held buffer
325 PCodeBuffConvertor< sal_uInt32, sal_uInt16 > aNewToLegacy( (sal_uInt8*)pCode, nCodeSize );
326 aNewToLegacy.convert();
327 pLegacyPCode = (char*)aNewToLegacy.GetBuffer();
328 nLegacyCodeSize = aNewToLegacy.GetSize();
329 r.Write( pLegacyPCode, nLegacyCodeSize );
331 else
333 r.Write( pCode, nCodeSize );
335 SbiCloseRecord( r, nPos );
337 // String-Pool?
338 if( nStrings )
340 nPos = SbiOpenRecord( r, B_STRINGPOOL, nStrings );
341 // For every String:
342 // sal_uInt32 Offset of the Strings in the Stringblock
343 short i;
345 for( i = 0; i < nStrings && SbiGood( r ); i++ )
347 r << (sal_uInt32) pStringOff[ i ];
349 // Then the String-Block
350 char* pByteStrings = new char[ nStringSize ];
351 for( i = 0; i < nStrings; i++ )
353 sal_uInt16 nOff = (sal_uInt16) pStringOff[ i ];
354 OString aStr(OUStringToOString(OUString(pStrings + nOff), eCharSet));
355 memcpy( pByteStrings + nOff, aStr.getStr(), (aStr.getLength() + 1) * sizeof( char ) );
357 r << (sal_uInt32) nStringSize;
358 r.Write( pByteStrings, nStringSize );
360 delete[] pByteStrings;
361 SbiCloseRecord( r, nPos );
363 // Set overall length
364 SbiCloseRecord( r, nStart );
365 if( !SbiGood( r ) )
367 bError = true;
369 return !bError;
372 /**************************************************************************
374 * Routines called by the compiler
376 **************************************************************************/
378 void SbiImage::MakeStrings( short nSize )
380 nStrings = 0;
381 nStringIdx = 0;
382 nStringOff = 0;
383 nStringSize = 1024;
384 pStrings = new sal_Unicode[ nStringSize ];
385 pStringOff = new sal_uInt32[ nSize ];
386 if( pStrings && pStringOff )
388 nStrings = nSize;
389 memset( pStringOff, 0, nSize * sizeof( sal_uInt32 ) );
390 memset( pStrings, 0, nStringSize * sizeof( sal_Unicode ) );
392 else
394 bError = true;
398 // Add a string to StringPool. The String buffer is dynamically
399 // growing in 1K-Steps
400 void SbiImage::AddString( const OUString& r )
402 if( nStringIdx >= nStrings )
404 bError = true;
406 if( !bError )
408 sal_Int32 len = r.getLength() + 1;
409 sal_uInt32 needed = nStringOff + len;
410 if( needed > 0xFFFFFF00L )
412 bError = true; // out of mem!
414 else if( needed > nStringSize )
416 sal_uInt32 nNewLen = needed + 1024;
417 nNewLen &= 0xFFFFFC00; // trim to 1K border
418 sal_Unicode* p = NULL;
419 if( (p = new sal_Unicode[ nNewLen ]) != NULL )
421 memcpy( p, pStrings, nStringSize * sizeof( sal_Unicode ) );
422 delete[] pStrings;
423 pStrings = p;
424 nStringSize = sal::static_int_cast< sal_uInt16 >(nNewLen);
426 else
428 bError = true;
431 if( !bError )
433 pStringOff[ nStringIdx++ ] = nStringOff;
434 memcpy( pStrings + nStringOff, r.getStr(), len * sizeof( sal_Unicode ) );
435 nStringOff = nStringOff + len;
436 // Last String? The update the size of the buffer
437 if( nStringIdx >= nStrings )
439 nStringSize = nStringOff;
445 // Add code block
446 // The block was fetched by the compiler from class SbBuffer and
447 // is already created with new. Additionally it contains all Integers
448 // in Big Endian format, so can be directly read/written.
449 void SbiImage::AddCode( char* p, sal_uInt32 s )
451 pCode = p;
452 nCodeSize = s;
455 // Add user type
456 void SbiImage::AddType(SbxObject* pObject)
458 if( !rTypes.Is() )
460 rTypes = new SbxArray;
462 SbxObject *pCopyObject = new SbxObject(*pObject);
463 rTypes->Insert (pCopyObject,rTypes->Count());
466 void SbiImage::AddEnum(SbxObject* pObject) // Register enum type
468 if( !rEnums.Is() )
470 rEnums = new SbxArray;
472 rEnums->Insert( pObject, rEnums->Count() );
476 /**************************************************************************
478 * Accessing the image
480 **************************************************************************/
482 // Note: IDs start with 1
483 OUString SbiImage::GetString( short nId ) const
485 if( nId && nId <= nStrings )
487 sal_uInt32 nOff = pStringOff[ nId - 1 ];
488 sal_Unicode* pStr = pStrings + nOff;
490 // #i42467: Special treatment for vbNullChar
491 if( *pStr == 0 )
493 sal_uInt32 nNextOff = (nId < nStrings) ? pStringOff[ nId ] : nStringOff;
494 sal_uInt32 nLen = nNextOff - nOff - 1;
495 if( nLen == 1 )
497 // Force length 1 and make char 0 afterwards
498 OUString aNullCharStr( (sal_Unicode)0);
499 return aNullCharStr;
502 else
504 return OUString(pStr);
507 return OUString();
510 const SbxObject* SbiImage::FindType (OUString aTypeName) const
512 return rTypes.Is() ? (SbxObject*)rTypes->Find(aTypeName,SbxCLASS_OBJECT) : NULL;
515 sal_uInt16 SbiImage::CalcLegacyOffset( sal_Int32 nOffset )
517 return SbiCodeGen::calcLegacyOffSet( (sal_uInt8*)pCode, nOffset ) ;
520 sal_uInt32 SbiImage::CalcNewOffset( sal_Int16 nOffset )
522 return SbiCodeGen::calcNewOffSet( (sal_uInt8*)pLegacyPCode, nOffset ) ;
525 void SbiImage::ReleaseLegacyBuffer()
527 delete[] pLegacyPCode;
528 pLegacyPCode = NULL;
529 nLegacyCodeSize = 0;
532 bool SbiImage::ExceedsLegacyLimits()
534 return ( nStringSize > 0xFF00L ) || ( CalcLegacyOffset( nCodeSize ) > 0xFF00L );
537 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */