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