1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tools/stream.hxx>
21 #include <tools/tenccvt.hxx>
22 #include <basic/sbx.hxx>
24 #include <string.h> // memset() etc
26 #include <codegen.hxx>
42 eCharSet
= osl_getThreadTextEncoding();
50 void SbiImage::Clear()
55 ReleaseLegacyBuffer();
64 eCharSet
= osl_getThreadTextEncoding();
69 /**************************************************************************
71 * Service-Routines for Load/Store
73 **************************************************************************/
75 bool SbiGood( SvStream
& r
)
77 return !r
.IsEof() && r
.GetError() == SVSTREAM_OK
;
81 sal_uIntPtr
SbiOpenRecord( SvStream
& r
, sal_uInt16 nSignature
, sal_uInt16 nElem
)
83 sal_uIntPtr nPos
= r
.Tell();
84 r
<< nSignature
<< (sal_Int32
) 0 << nElem
;
89 void SbiCloseRecord( SvStream
& r
, sal_uIntPtr nOff
)
91 sal_uIntPtr nPos
= r
.Tell();
93 r
<< (sal_Int32
) ( nPos
- nOff
- 8 );
97 /**************************************************************************
101 **************************************************************************/
103 bool SbiImage::Load( SvStream
& r
, sal_uInt32
& nVersion
)
106 sal_uInt16 nSign
, nCount
;
107 sal_uInt32 nLen
, nOff
;
110 // Read Master-Record
111 r
>> nSign
>> nLen
>> nCount
;
112 sal_uIntPtr nLast
= r
.Tell() + nLen
;
113 sal_uInt32 nCharSet
; // System charset
115 sal_uInt16 nReserved1
;
116 sal_uInt32 nReserved2
;
117 sal_uInt32 nReserved3
;
118 bool bBadVer
= false;
119 if( nSign
== B_MODULE
)
121 r
>> nVersion
>> nCharSet
>> lDimBase
122 >> nFlags
>> nReserved1
>> nReserved2
>> nReserved3
;
123 eCharSet
= (CharSet
) nCharSet
;
124 eCharSet
= GetSOLoadTextEncoding( eCharSet
);
125 bBadVer
= ( nVersion
> B_CURVERSION
);
126 nDimBase
= (sal_uInt16
) lDimBase
;
129 bool bLegacy
= ( nVersion
< B_EXT_IMG_VERSION
);
132 while( ( nNext
= r
.Tell() ) < nLast
)
135 r
>> nSign
>> nLen
>> nCount
;
137 if( r
.GetError() == SVSTREAM_OK
)
142 aName
= r
.ReadUniOrByteString(eCharSet
);
145 aComment
= r
.ReadUniOrByteString(eCharSet
);
149 aOUSource
= r
.ReadUniOrByteString(eCharSet
);
154 for( sal_uInt16 j
= 0 ; j
< nCount
; j
++ )
156 aOUSource
+= r
.ReadUniOrByteString(eCharSet
);
162 pCode
= new char[ nLen
];
164 r
.Read( pCode
, nCodeSize
);
167 ReleaseLegacyBuffer(); // release any previously held buffer
168 nLegacyCodeSize
= (sal_uInt16
) nCodeSize
;
169 pLegacyPCode
= pCode
;
171 PCodeBuffConvertor
< sal_uInt16
, sal_uInt32
> aLegacyToNew( (sal_uInt8
*)pLegacyPCode
, nLegacyCodeSize
);
172 aLegacyToNew
.convert();
173 pCode
= (char*)aLegacyToNew
.GetBuffer();
174 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.
192 MakeStrings( nCount
);
194 for( i
= 0; i
< nStrings
&& SbiGood( r
); i
++ )
197 pStringOff
[ i
] = (sal_uInt16
) nOff
;
203 pStrings
= new sal_Unicode
[ nLen
];
204 nStringSize
= (sal_uInt16
) nLen
;
206 char* pByteStrings
= new char[ nLen
];
207 r
.Read( pByteStrings
, nStringSize
);
208 for( short j
= 0; j
< nStrings
; j
++ )
210 sal_uInt16 nOff2
= (sal_uInt16
) pStringOff
[ j
];
211 OUString
aStr( pByteStrings
+ nOff2
, strlen(pByteStrings
+ nOff2
), eCharSet
);
212 memcpy( pStrings
+ nOff2
, aStr
.getStr(), (aStr
.getLength() + 1) * sizeof( sal_Unicode
) );
214 delete[] pByteStrings
;
238 bool SbiImage::Save( SvStream
& r
, sal_uInt32 nVer
)
240 bool bLegacy
= ( nVer
< B_EXT_IMG_VERSION
);
242 // detect if old code exceeds legacy limits
243 // if so, then disallow save
244 if ( bLegacy
&& ExceedsLegacyLimits() )
247 aEmptyImg
.aName
= aName
;
248 aEmptyImg
.Save( r
, B_LEGACYVERSION
);
251 // First of all the header
252 sal_uIntPtr nStart
= SbiOpenRecord( r
, B_MODULE
, 1 );
255 eCharSet
= GetSOStoreTextEncoding( eCharSet
);
258 r
<< (sal_Int32
) B_LEGACYVERSION
;
262 r
<< (sal_Int32
) B_CURVERSION
;
264 r
<< (sal_Int32
) eCharSet
265 << (sal_Int32
) nDimBase
266 << (sal_Int16
) nFlags
272 if( !aName
.isEmpty() && SbiGood( r
) )
274 nPos
= SbiOpenRecord( r
, B_NAME
, 1 );
275 r
.WriteUniOrByteString( aName
, eCharSet
);
276 SbiCloseRecord( r
, nPos
);
279 if( !aComment
.isEmpty() && SbiGood( r
) )
281 nPos
= SbiOpenRecord( r
, B_COMMENT
, 1 );
282 r
.WriteUniOrByteString( aComment
, eCharSet
);
283 SbiCloseRecord( r
, nPos
);
286 if( !aOUSource
.isEmpty() && SbiGood( r
) )
288 nPos
= SbiOpenRecord( r
, B_SOURCE
, 1 );
290 sal_Int32 nLen
= aOUSource
.getLength();
291 const sal_Int32 nMaxUnitSize
= STRING_MAXLEN
- 1;
292 if( nLen
> STRING_MAXLEN
)
294 aTmp
= aOUSource
.copy( 0, nMaxUnitSize
);
300 r
.WriteUniOrByteString( aTmp
, eCharSet
);
301 SbiCloseRecord( r
, nPos
);
303 if( nLen
> STRING_MAXLEN
)
305 sal_Int32 nRemainingLen
= nLen
- nMaxUnitSize
;
306 sal_uInt16 nUnitCount
= sal_uInt16( (nRemainingLen
+ nMaxUnitSize
- 1) / nMaxUnitSize
);
307 nPos
= SbiOpenRecord( r
, B_EXTSOURCE
, nUnitCount
);
308 for( sal_uInt16 i
= 0 ; i
< nUnitCount
; i
++ )
310 sal_Int32 nCopyLen
= (nRemainingLen
> nMaxUnitSize
) ? nMaxUnitSize
: nRemainingLen
;
311 OUString aTmp2
= aOUSource
.copy( (i
+1) * nMaxUnitSize
, nCopyLen
);
312 nRemainingLen
-= nCopyLen
;
313 r
.WriteUniOrByteString( aTmp2
, eCharSet
);
315 SbiCloseRecord( r
, nPos
);
319 if( pCode
&& SbiGood( r
) )
321 nPos
= SbiOpenRecord( r
, B_PCODE
, 1 );
324 ReleaseLegacyBuffer(); // release any previously held buffer
325 PCodeBuffConvertor
< sal_uInt32
, sal_uInt16
> aNewToLegacy( (sal_uInt8
*)pCode
, nCodeSize
);
326 aNewToLegacy
.convert();
327 pLegacyPCode
= (char*)aNewToLegacy
.GetBuffer();
328 nLegacyCodeSize
= aNewToLegacy
.GetSize();
329 r
.Write( pLegacyPCode
, nLegacyCodeSize
);
333 r
.Write( pCode
, nCodeSize
);
335 SbiCloseRecord( r
, nPos
);
340 nPos
= SbiOpenRecord( r
, B_STRINGPOOL
, nStrings
);
342 // sal_uInt32 Offset of the Strings in the Stringblock
345 for( i
= 0; i
< nStrings
&& SbiGood( r
); i
++ )
347 r
<< (sal_uInt32
) pStringOff
[ i
];
349 // Then the String-Block
350 char* pByteStrings
= new char[ nStringSize
];
351 for( i
= 0; i
< nStrings
; i
++ )
353 sal_uInt16 nOff
= (sal_uInt16
) pStringOff
[ i
];
354 OString
aStr(OUStringToOString(OUString(pStrings
+ nOff
), eCharSet
));
355 memcpy( pByteStrings
+ nOff
, aStr
.getStr(), (aStr
.getLength() + 1) * sizeof( char ) );
357 r
<< (sal_uInt32
) nStringSize
;
358 r
.Write( pByteStrings
, nStringSize
);
360 delete[] pByteStrings
;
361 SbiCloseRecord( r
, nPos
);
363 // Set overall length
364 SbiCloseRecord( r
, nStart
);
372 /**************************************************************************
374 * Routines called by the compiler
376 **************************************************************************/
378 void SbiImage::MakeStrings( short nSize
)
384 pStrings
= new sal_Unicode
[ nStringSize
];
385 pStringOff
= new sal_uInt32
[ nSize
];
386 if( pStrings
&& pStringOff
)
389 memset( pStringOff
, 0, nSize
* sizeof( sal_uInt32
) );
390 memset( pStrings
, 0, nStringSize
* sizeof( sal_Unicode
) );
398 // Add a string to StringPool. The String buffer is dynamically
399 // growing in 1K-Steps
400 void SbiImage::AddString( const OUString
& r
)
402 if( nStringIdx
>= nStrings
)
408 sal_Int32 len
= r
.getLength() + 1;
409 sal_uInt32 needed
= nStringOff
+ len
;
410 if( needed
> 0xFFFFFF00L
)
412 bError
= true; // out of mem!
414 else if( needed
> nStringSize
)
416 sal_uInt32 nNewLen
= needed
+ 1024;
417 nNewLen
&= 0xFFFFFC00; // trim to 1K border
418 sal_Unicode
* p
= NULL
;
419 if( (p
= new sal_Unicode
[ nNewLen
]) != NULL
)
421 memcpy( p
, pStrings
, nStringSize
* sizeof( sal_Unicode
) );
424 nStringSize
= sal::static_int_cast
< sal_uInt16
>(nNewLen
);
433 pStringOff
[ nStringIdx
++ ] = nStringOff
;
434 memcpy( pStrings
+ nStringOff
, r
.getStr(), len
* sizeof( sal_Unicode
) );
435 nStringOff
= nStringOff
+ len
;
436 // Last String? The update the size of the buffer
437 if( nStringIdx
>= nStrings
)
439 nStringSize
= nStringOff
;
446 // The block was fetched by the compiler from class SbBuffer and
447 // is already created with new. Additionally it contains all Integers
448 // in Big Endian format, so can be directly read/written.
449 void SbiImage::AddCode( char* p
, sal_uInt32 s
)
456 void SbiImage::AddType(SbxObject
* pObject
)
460 rTypes
= new SbxArray
;
462 SbxObject
*pCopyObject
= new SbxObject(*pObject
);
463 rTypes
->Insert (pCopyObject
,rTypes
->Count());
466 void SbiImage::AddEnum(SbxObject
* pObject
) // Register enum type
470 rEnums
= new SbxArray
;
472 rEnums
->Insert( pObject
, rEnums
->Count() );
476 /**************************************************************************
478 * Accessing the image
480 **************************************************************************/
482 // Note: IDs start with 1
483 OUString
SbiImage::GetString( short nId
) const
485 if( nId
&& nId
<= nStrings
)
487 sal_uInt32 nOff
= pStringOff
[ nId
- 1 ];
488 sal_Unicode
* pStr
= pStrings
+ nOff
;
490 // #i42467: Special treatment for vbNullChar
493 sal_uInt32 nNextOff
= (nId
< nStrings
) ? pStringOff
[ nId
] : nStringOff
;
494 sal_uInt32 nLen
= nNextOff
- nOff
- 1;
497 // Force length 1 and make char 0 afterwards
498 OUString
aNullCharStr( (sal_Unicode
)0);
504 return OUString(pStr
);
510 const SbxObject
* SbiImage::FindType (OUString aTypeName
) const
512 return rTypes
.Is() ? (SbxObject
*)rTypes
->Find(aTypeName
,SbxCLASS_OBJECT
) : NULL
;
515 sal_uInt16
SbiImage::CalcLegacyOffset( sal_Int32 nOffset
)
517 return SbiCodeGen::calcLegacyOffSet( (sal_uInt8
*)pCode
, nOffset
) ;
520 sal_uInt32
SbiImage::CalcNewOffset( sal_Int16 nOffset
)
522 return SbiCodeGen::calcNewOffSet( (sal_uInt8
*)pLegacyPCode
, nOffset
) ;
525 void SbiImage::ReleaseLegacyBuffer()
527 delete[] pLegacyPCode
;
532 bool SbiImage::ExceedsLegacyLimits()
534 return ( nStringSize
> 0xFF00L
) || ( CalcLegacyOffset( nCodeSize
) > 0xFF00L
);
537 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */