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>
SbiImage()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
~SbiImage()51 SbiImage::~SbiImage()
52 {
53 Clear();
54 }
55
Clear()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
SbiGood(SvStream & r)81 sal_Bool SbiGood( SvStream& r )
82 {
83 return sal_Bool( !r.IsEof() && r.GetError() == SVSTREAM_OK );
84 }
85
86 // Open Record
SbiOpenRecord(SvStream & r,sal_uInt16 nSignature,sal_uInt16 nElem)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
SbiCloseRecord(SvStream & r,sal_uIntPtr nOff)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
Load(SvStream & r)111 sal_Bool SbiImage::Load( SvStream& r )
112 {
113 sal_uInt32 nVersion = 0; // Versionsnumber
114 return Load( r, nVersion );
115 }
Load(SvStream & r,sal_uInt32 & nVersion)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
Save(SvStream & r,sal_uInt32 nVer)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.isEmpty() && 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
MakeStrings(short nSize)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
AddString(const String & r)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.
AddCode(char * p,sal_uInt32 s)454 void SbiImage::AddCode( char* p, sal_uInt32 s )
455 {
456 pCode = p;
457 nCodeSize = s;
458 }
459
460 // Add user type
AddType(SbxObject * pObject)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
AddEnum(SbxObject * pObject)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
GetString(short nId) const484 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
FindType(String aTypeName) const513 const SbxObject* SbiImage::FindType (String aTypeName) const
514 {
515 return rTypes.Is() ? (SbxObject*)rTypes->Find(aTypeName,SbxCLASS_OBJECT) : NULL;
516 }
517
CalcLegacyOffset(sal_Int32 nOffset)518 sal_uInt16 SbiImage::CalcLegacyOffset( sal_Int32 nOffset )
519 {
520 return SbiCodeGen::calcLegacyOffSet( (sal_uInt8*)pCode, nOffset ) ;
521 }
522
CalcNewOffset(sal_Int16 nOffset)523 sal_uInt32 SbiImage::CalcNewOffset( sal_Int16 nOffset )
524 {
525 return SbiCodeGen::calcNewOffSet( (sal_uInt8*)pLegacyPCode, nOffset ) ;
526 }
527
ReleaseLegacyBuffer()528 void SbiImage::ReleaseLegacyBuffer()
529 {
530 delete[] pLegacyPCode;
531 pLegacyPCode = NULL;
532 nLegacyCodeSize = 0;
533 }
534
ExceedsLegacyLimits()535 sal_Bool SbiImage::ExceedsLegacyLimits()
536 {
537 if ( ( nStringSize > 0xFF00L ) || ( CalcLegacyOffset( nCodeSize ) > 0xFF00L ) )
538 return sal_True;
539 return sal_False;
540 }
541