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