xref: /trunk/main/oox/inc/oox/helper/helper.hxx (revision e3508121)
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 #ifndef OOX_HELPER_HELPER_HXX
25 #define OOX_HELPER_HELPER_HXX
26 
27 #include <algorithm>
28 #include <limits>
29 #include <boost/static_assert.hpp>
30 #include <osl/endian.h>
31 #include <rtl/math.hxx>
32 #include <rtl/string.hxx>
33 #include <rtl/ustring.hxx>
34 #include <string.h>
35 
36 namespace oox {
37 
38 // Helper macros ==============================================================
39 
40 /** Expands to the number of elements in a STATIC data array. */
41 #define STATIC_ARRAY_SIZE( array ) \
42     (sizeof(array)/sizeof(*(array)))
43 
44 /** Expands to a pointer behind the last element of a STATIC data array (like
45     STL end()). */
46 #define STATIC_ARRAY_END( array ) \
47     ((array)+STATIC_ARRAY_SIZE(array))
48 
49 /** Expands to the 'index'-th element of a STATIC data array, or to 'def', if
50     'index' is out of the array limits. */
51 #define STATIC_ARRAY_SELECT( array, index, def ) \
52     ((static_cast<size_t>(index) < STATIC_ARRAY_SIZE(array)) ? ((array)[static_cast<size_t>(index)]) : (def))
53 
54 /** Expands to a temporary ::rtl::OString, created from a literal(!) character
55     array. */
56 #define CREATE_OSTRING( ascii ) \
57     ::rtl::OString( RTL_CONSTASCII_STRINGPARAM( ascii ) )
58 
59 /** Expands to a temporary ::rtl::OUString, created from a literal(!) ASCII(!)
60     character array. */
61 #define CREATE_OUSTRING( ascii ) \
62     ::rtl::OUString::intern( RTL_CONSTASCII_USTRINGPARAM( ascii ) )
63 
64 /** Convert an OUString to an ASCII C string. Use for debug purposes only. */
65 #define OUSTRING_TO_CSTR( str ) \
66     ::rtl::OUStringToOString( str, RTL_TEXTENCODING_ASCII_US ).getStr()
67 
68 // Common constants ===========================================================
69 
70 const sal_uInt8 WINDOWS_CHARSET_ANSI        = 0;
71 const sal_uInt8 WINDOWS_CHARSET_DEFAULT     = 1;
72 const sal_uInt8 WINDOWS_CHARSET_SYMBOL      = 2;
73 const sal_uInt8 WINDOWS_CHARSET_APPLE_ROMAN = 77;
74 const sal_uInt8 WINDOWS_CHARSET_SHIFTJIS    = 128;
75 const sal_uInt8 WINDOWS_CHARSET_HANGEUL     = 129;
76 const sal_uInt8 WINDOWS_CHARSET_JOHAB       = 130;
77 const sal_uInt8 WINDOWS_CHARSET_GB2312      = 134;
78 const sal_uInt8 WINDOWS_CHARSET_BIG5        = 136;
79 const sal_uInt8 WINDOWS_CHARSET_GREEK       = 161;
80 const sal_uInt8 WINDOWS_CHARSET_TURKISH     = 162;
81 const sal_uInt8 WINDOWS_CHARSET_VIETNAMESE  = 163;
82 const sal_uInt8 WINDOWS_CHARSET_HEBREW      = 177;
83 const sal_uInt8 WINDOWS_CHARSET_ARABIC      = 178;
84 const sal_uInt8 WINDOWS_CHARSET_BALTIC      = 186;
85 const sal_uInt8 WINDOWS_CHARSET_RUSSIAN     = 204;
86 const sal_uInt8 WINDOWS_CHARSET_THAI        = 222;
87 const sal_uInt8 WINDOWS_CHARSET_EASTERN     = 238;
88 const sal_uInt8 WINDOWS_CHARSET_OEM         = 255;
89 
90 // ----------------------------------------------------------------------------
91 
92 const sal_Int32 API_RGB_TRANSPARENT         = -1;       /// Transparent color for API calls.
93 const sal_Int32 API_RGB_BLACK               = 0x00000;  /// Black color for API calls.
94 const sal_Int32 API_RGB_WHITE               = 0xFFFFF;  /// White color for API calls.
95 
96 const sal_Int16 API_LINE_NONE               = 0;
97 const sal_Int16 API_LINE_HAIR               = 2;
98 const sal_Int16 API_LINE_THIN               = 35;
99 const sal_Int16 API_LINE_MEDIUM             = 88;
100 const sal_Int16 API_LINE_THICK              = 141;
101 
102 const sal_Int16 API_ESCAPE_NONE             = 0;        /// No escapement.
103 const sal_Int16 API_ESCAPE_SUPERSCRIPT      = 101;      /// Superscript: raise characters automatically (magic value 101).
104 const sal_Int16 API_ESCAPE_SUBSCRIPT        = -101;     /// Subscript: lower characters automatically (magic value -101).
105 
106 const sal_Int8 API_ESCAPEHEIGHT_NONE        = 100;      /// Relative character height if not escaped.
107 const sal_Int8 API_ESCAPEHEIGHT_DEFAULT     = 58;       /// Relative character height if escaped.
108 
109 // ============================================================================
110 
111 // Limitate values ------------------------------------------------------------
112 
113 template< typename ReturnType, typename Type >
getLimitedValue(Type nValue,Type nMin,Type nMax)114 inline ReturnType getLimitedValue( Type nValue, Type nMin, Type nMax )
115 {
116     return static_cast< ReturnType >( ::std::min( ::std::max( nValue, nMin ), nMax ) );
117 }
118 
119 template< typename ReturnType, typename Type >
getIntervalValue(Type nValue,Type nBegin,Type nEnd)120 inline ReturnType getIntervalValue( Type nValue, Type nBegin, Type nEnd )
121 {
122 //    this BOOST_STATIC_ASSERT fails with suncc
123 //    BOOST_STATIC_ASSERT( ::std::numeric_limits< Type >::is_integer );
124     Type nInterval = nEnd - nBegin;
125     Type nCount = (nValue < nBegin) ? -((nBegin - nValue - 1) / nInterval + 1) : ((nValue - nBegin) / nInterval);
126     return static_cast< ReturnType >( nValue - nCount * nInterval );
127 }
128 
129 template< typename ReturnType >
getDoubleIntervalValue(double fValue,double fBegin,double fEnd)130 inline ReturnType getDoubleIntervalValue( double fValue, double fBegin, double fEnd )
131 {
132     double fInterval = fEnd - fBegin;
133     double fCount = (fValue < fBegin) ? -(::rtl::math::approxFloor( (fBegin - fValue - 1.0) / fInterval ) + 1.0) : ::rtl::math::approxFloor( (fValue - fBegin) / fInterval );
134     return static_cast< ReturnType >( fValue - fCount * fInterval );
135 }
136 
137 // Read from bitfields --------------------------------------------------------
138 
139 /** Returns true, if at least one of the bits set in nMask is set in nBitField. */
140 template< typename Type >
getFlag(Type nBitField,Type nMask)141 inline bool getFlag( Type nBitField, Type nMask )
142 {
143     return (nBitField & nMask) != 0;
144 }
145 
146 /** Returns nSet, if at least one bit of nMask is set in nBitField, otherwise nUnset. */
147 template< typename ReturnType, typename Type >
getFlagValue(Type nBitField,Type nMask,ReturnType nSet,ReturnType nUnset)148 inline ReturnType getFlagValue( Type nBitField, Type nMask, ReturnType nSet, ReturnType nUnset )
149 {
150     return getFlag( nBitField, nMask ) ? nSet : nUnset;
151 }
152 
153 /** Extracts a value from a bit field.
154 
155     Returns the data fragment from nBitField, that starts at bit nStartBit
156     (0-based, bit 0 is rightmost) with the width of nBitCount. The returned
157     value will be right-aligned (normalized).
158     For instance: extractValue<T>(0x4321,8,4) returns 3 (value in bits 8-11).
159  */
160 template< typename ReturnType, typename Type >
extractValue(Type nBitField,sal_uInt8 nStartBit,sal_uInt8 nBitCount)161 inline ReturnType extractValue( Type nBitField, sal_uInt8 nStartBit, sal_uInt8 nBitCount )
162 {
163     sal_uInt64 nMask = 1; nMask <<= nBitCount; --nMask;
164     return static_cast< ReturnType >( nMask & (nBitField >> nStartBit) );
165 }
166 
167 // Write to bitfields ---------------------------------------------------------
168 
169 /** Sets or clears (according to bSet) all set bits of nMask in ornBitField. */
170 template< typename Type >
setFlag(Type & ornBitField,Type nMask,bool bSet=true)171 inline void setFlag( Type& ornBitField, Type nMask, bool bSet = true )
172 {
173     if( bSet ) ornBitField |= nMask; else ornBitField &= ~nMask;
174 }
175 
176 /** Inserts a value into a bitfield.
177 
178     Inserts the lower nBitCount bits of nValue into ornBitField, starting
179     there at bit nStartBit. Other contents of ornBitField keep unchanged.
180  */
181 template< typename Type, typename InsertType >
insertValue(Type & ornBitField,InsertType nValue,sal_uInt8 nStartBit,sal_uInt8 nBitCount)182 void insertValue( Type& ornBitField, InsertType nValue, sal_uInt8 nStartBit, sal_uInt8 nBitCount )
183 {
184     sal_uInt64 nMask = 1; nMask <<= nBitCount; --nMask;
185     Type nNewValue = static_cast< Type >( nValue & nMask );
186     (ornBitField &= ~(nMask << nStartBit)) |= (nNewValue << nStartBit);
187 }
188 
189 // ============================================================================
190 
191 /** Optional value, similar to ::boost::optional<>, with convenience accessors.
192  */
193 template< typename Type >
194 class OptValue
195 {
196 public:
OptValue()197     inline explicit     OptValue() : maValue(), mbHasValue( false ) {}
OptValue(const Type & rValue)198     inline explicit     OptValue( const Type& rValue ) : maValue( rValue ), mbHasValue( true ) {}
OptValue(bool bHasValue,const Type & rValue)199     inline explicit     OptValue( bool bHasValue, const Type& rValue ) : maValue( rValue ), mbHasValue( bHasValue ) {}
200 
has() const201     inline bool         has() const { return mbHasValue; }
operator !() const202     inline bool         operator!() const { return !mbHasValue; }
differsFrom(const Type & rValue) const203     inline bool         differsFrom( const Type& rValue ) const { return mbHasValue && (maValue != rValue); }
204 
get() const205     inline const Type&  get() const { return maValue; }
get(const Type & rDefValue) const206     inline const Type&  get( const Type& rDefValue ) const { return mbHasValue ? maValue : rDefValue; }
207 
reset()208     inline void         reset() { mbHasValue = false; }
set(const Type & rValue)209     inline void         set( const Type& rValue ) { maValue = rValue; mbHasValue = true; }
use()210     inline Type&        use() { mbHasValue = true; return maValue; }
211 
operator =(const Type & rValue)212     inline OptValue&    operator=( const Type& rValue ) { set( rValue ); return *this; }
assignIfUsed(const OptValue & rValue)213     inline void         assignIfUsed( const OptValue& rValue ) { if( rValue.mbHasValue ) set( rValue.maValue ); }
214 
215 private:
216     Type                maValue;
217     bool                mbHasValue;
218 };
219 
220 // ============================================================================
221 
222 /** Provides platform independent functions to convert from or to little-endian
223     byte order, e.g. for reading data from or writing data to memory or a
224     binary stream.
225 
226     On big-endian platforms, the byte order in the passed values is swapped,
227     this can be used for converting big-endian to and from little-endian data.
228 
229     On little-endian platforms, the conversion functions are implemented empty,
230     thus compilers should completely optimize away the function call.
231  */
232 class ByteOrderConverter
233 {
234 public:
235 #ifdef OSL_BIGENDIAN
convertLittleEndian(sal_Int8 &)236     inline static void  convertLittleEndian( sal_Int8& ) {}     // present for usage in templates
convertLittleEndian(sal_uInt8 &)237     inline static void  convertLittleEndian( sal_uInt8& ) {}    // present for usage in templates
convertLittleEndian(sal_Int16 & rnValue)238     inline static void  convertLittleEndian( sal_Int16& rnValue )  { swap2( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_uInt16 & rnValue)239     inline static void  convertLittleEndian( sal_uInt16& rnValue ) { swap2( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_Int32 & rnValue)240     inline static void  convertLittleEndian( sal_Int32& rnValue )  { swap4( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_uInt32 & rnValue)241     inline static void  convertLittleEndian( sal_uInt32& rnValue ) { swap4( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_Int64 & rnValue)242     inline static void  convertLittleEndian( sal_Int64& rnValue )  { swap8( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_uInt64 & rnValue)243     inline static void  convertLittleEndian( sal_uInt64& rnValue ) { swap8( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(float & rfValue)244     inline static void  convertLittleEndian( float& rfValue )      { swap4( reinterpret_cast< sal_uInt8* >( &rfValue ) ); }
convertLittleEndian(double & rfValue)245     inline static void  convertLittleEndian( double& rfValue )     { swap8( reinterpret_cast< sal_uInt8* >( &rfValue ) ); }
246 
247     template< typename Type >
248     inline static void  convertLittleEndianArray( Type* pnArray, size_t nElemCount );
249 
convertLittleEndianArray(sal_Int8 *,size_t)250     inline static void  convertLittleEndianArray( sal_Int8*, size_t ) {}
convertLittleEndianArray(sal_uInt8 *,size_t)251     inline static void  convertLittleEndianArray( sal_uInt8*, size_t ) {}
252 
253 #else
254     template< typename Type >
255     inline static void  convertLittleEndian( Type& ) {}
256 
257     template< typename Type >
258     inline static void  convertLittleEndianArray( Type*, size_t ) {}
259 
260 #endif
261 
262     /** Reads a value from memory, assuming memory buffer in little-endian.
263         @param ornValue  (out-parameter) Contains the value read from memory.
264         @param pSrcBuffer  The memory buffer to read the value from.
265      */
266     template< typename Type >
267     inline static void  readLittleEndian( Type& ornValue, const void* pSrcBuffer );
268 
269     /** Writes a value to memory, while converting it to little-endian.
270         @param pDstBuffer  The memory buffer to write the value to.
271         @param nValue  The value to be written to memory in little-endian.
272      */
273     template< typename Type >
274     inline static void  writeLittleEndian( void* pDstBuffer, Type nValue );
275 
276 #ifdef OSL_BIGENDIAN
277 private:
278     inline static void  swap2( sal_uInt8* pnData );
279     inline static void  swap4( sal_uInt8* pnData );
280     inline static void  swap8( sal_uInt8* pnData );
281 #endif
282 };
283 
284 // ----------------------------------------------------------------------------
285 
286 template< typename Type >
readLittleEndian(Type & ornValue,const void * pSrcBuffer)287 inline void ByteOrderConverter::readLittleEndian( Type& ornValue, const void* pSrcBuffer )
288 {
289     memcpy( &ornValue, pSrcBuffer, sizeof( Type ) );
290     convertLittleEndian( ornValue );
291 }
292 
293 template< typename Type >
writeLittleEndian(void * pDstBuffer,Type nValue)294 inline void ByteOrderConverter::writeLittleEndian( void* pDstBuffer, Type nValue )
295 {
296     convertLittleEndian( nValue );
297     memcpy( pDstBuffer, &nValue, sizeof( Type ) );
298 }
299 
300 #ifdef OSL_BIGENDIAN
301 template< typename Type >
convertLittleEndianArray(Type * pnArray,size_t nElemCount)302 inline void ByteOrderConverter::convertLittleEndianArray( Type* pnArray, size_t nElemCount )
303 {
304     for( Type* pnArrayEnd = pnArray + nElemCount; pnArray != pnArrayEnd; ++pnArray )
305         convertLittleEndian( *pnArray );
306 }
307 
swap2(sal_uInt8 * pnData)308 inline void ByteOrderConverter::swap2( sal_uInt8* pnData )
309 {
310     ::std::swap( pnData[ 0 ], pnData[ 1 ] );
311 }
312 
swap4(sal_uInt8 * pnData)313 inline void ByteOrderConverter::swap4( sal_uInt8* pnData )
314 {
315     ::std::swap( pnData[ 0 ], pnData[ 3 ] );
316     ::std::swap( pnData[ 1 ], pnData[ 2 ] );
317 }
318 
swap8(sal_uInt8 * pnData)319 inline void ByteOrderConverter::swap8( sal_uInt8* pnData )
320 {
321     ::std::swap( pnData[ 0 ], pnData[ 7 ] );
322     ::std::swap( pnData[ 1 ], pnData[ 6 ] );
323     ::std::swap( pnData[ 2 ], pnData[ 5 ] );
324     ::std::swap( pnData[ 3 ], pnData[ 4 ] );
325 }
326 #endif
327 
328 // ============================================================================
329 
330 } // namespace oox
331 
332 #endif
333