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