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