xref: /aoo41x/main/basic/source/classes/image.cxx (revision cdf0e10c)
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