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 #ifndef INCLUDED_OOX_HELPER_HELPER_HXX
21 #define INCLUDED_OOX_HELPER_HELPER_HXX
22 
23 #include <sal/config.h>
24 
25 #include <cstring>
26 #include <limits>
27 
28 #include <osl/endian.h>
29 #include <rtl/math.hxx>
30 #include <rtl/textenc.h>
31 #include <sal/macros.h>
32 #include <sal/types.h>
33 #include <tools/color.hxx>
34 
35 namespace oox {
36 
37 // Helper macros ==============================================================
38 
39 /** Expands to the 'index'-th element of a STATIC data array, or to 'def', if
40     'index' is out of the array limits. */
41 #define STATIC_ARRAY_SELECT( array, index, def ) \
42     ((static_cast<size_t>(index) < SAL_N_ELEMENTS(array)) ? ((array)[static_cast<size_t>(index)]) : (def))
43 
44 // Common constants ===========================================================
45 
46 const sal_uInt8 WINDOWS_CHARSET_ANSI        = 0;
47 const sal_uInt8 WINDOWS_CHARSET_DEFAULT     = 1;
48 const sal_uInt8 WINDOWS_CHARSET_SYMBOL      = 2;
49 const sal_uInt8 WINDOWS_CHARSET_APPLE_ROMAN = 77;
50 const sal_uInt8 WINDOWS_CHARSET_SHIFTJIS    = 128;
51 const sal_uInt8 WINDOWS_CHARSET_HANGEUL     = 129;
52 const sal_uInt8 WINDOWS_CHARSET_JOHAB       = 130;
53 const sal_uInt8 WINDOWS_CHARSET_GB2312      = 134;
54 const sal_uInt8 WINDOWS_CHARSET_BIG5        = 136;
55 const sal_uInt8 WINDOWS_CHARSET_GREEK       = 161;
56 const sal_uInt8 WINDOWS_CHARSET_TURKISH     = 162;
57 const sal_uInt8 WINDOWS_CHARSET_VIETNAMESE  = 163;
58 const sal_uInt8 WINDOWS_CHARSET_HEBREW      = 177;
59 const sal_uInt8 WINDOWS_CHARSET_ARABIC      = 178;
60 const sal_uInt8 WINDOWS_CHARSET_BALTIC      = 186;
61 const sal_uInt8 WINDOWS_CHARSET_RUSSIAN     = 204;
62 const sal_uInt8 WINDOWS_CHARSET_THAI        = 222;
63 const sal_uInt8 WINDOWS_CHARSET_EASTERN     = 238;
64 const sal_uInt8 WINDOWS_CHARSET_OEM         = 255;
65 
66 
67 const ::Color API_RGB_TRANSPARENT         (0xffffffff); ///< Transparent color for API calls.
68 const sal_uInt32 UNSIGNED_RGB_TRANSPARENT = static_cast<sal_uInt32>(-1); ///< Transparent color for unsigned int32 places.
69 const ::Color API_RGB_BLACK               (0x000000);  ///< Black color for API calls.
70 const ::Color API_RGB_GRAY                (0x808080);  ///< Gray color for API calls.
71 const ::Color API_RGB_WHITE               (0xFFFFFF);  ///< White color for API calls.
72 
73 const sal_Int16 API_LINE_SOLID              = 0;
74 const sal_Int16 API_LINE_DOTTED             = 1;
75 const sal_Int16 API_LINE_DASHED             = 2;
76 const sal_Int16 API_FINE_LINE_DASHED        = 14;
77 
78 const sal_Int16 API_LINE_NONE               = 0;
79 const sal_Int16 API_LINE_HAIR               = 2;
80 const sal_Int16 API_LINE_THIN               = 35;
81 const sal_Int16 API_LINE_MEDIUM             = 88;
82 const sal_Int16 API_LINE_THICK              = 141;
83 
84 const sal_Int16 API_ESCAPE_NONE             = 0;        ///< No escapement.
85 const sal_Int16 API_ESCAPE_SUPERSCRIPT      = 101;      ///< Superscript: raise characters automatically (magic value 101).
86 const sal_Int16 API_ESCAPE_SUBSCRIPT        = -101;     ///< Subscript: lower characters automatically (magic value -101).
87 
88 const sal_Int8 API_ESCAPEHEIGHT_NONE        = 100;      ///< Relative character height if not escaped.
89 const sal_Int8 API_ESCAPEHEIGHT_DEFAULT     = 58;       ///< Relative character height if escaped.
90 
91 
92 // Limitate values ------------------------------------------------------------
93 
94 template< typename ReturnType, typename Type >
getLimitedValue(Type nValue,Type nMin,Type nMax)95 inline ReturnType getLimitedValue( Type nValue, Type nMin, Type nMax )
96 {
97     return static_cast< ReturnType >( ::std::min( ::std::max( nValue, nMin ), nMax ) );
98 }
99 
100 template< typename ReturnType, typename Type >
getIntervalValue(Type nValue,Type nBegin,Type nEnd)101 inline ReturnType getIntervalValue( Type nValue, Type nBegin, Type nEnd )
102 {
103     static_assert(::std::numeric_limits< Type >::is_integer, "is integer");
104     Type nInterval = nEnd - nBegin;
105     Type nCount = (nValue < nBegin) ? -((nBegin - nValue - 1) / nInterval + 1) : ((nValue - nBegin) / nInterval);
106     return static_cast< ReturnType >( nValue - nCount * nInterval );
107 }
108 
109 template< typename ReturnType >
getDoubleIntervalValue(double fValue,double fBegin,double fEnd)110 inline ReturnType getDoubleIntervalValue( double fValue, double fBegin, double fEnd )
111 {
112     double fInterval = fEnd - fBegin;
113     double fCount = (fValue < fBegin) ? -(::rtl::math::approxFloor( (fBegin - fValue - 1.0) / fInterval ) + 1.0) : ::rtl::math::approxFloor( (fValue - fBegin) / fInterval );
114     return static_cast< ReturnType >( fValue - fCount * fInterval );
115 }
116 
117 // Read from bitfields --------------------------------------------------------
118 
119 /** Returns true, if at least one of the bits set in nMask is set in nBitField. */
120 template< typename Type >
getFlag(Type nBitField,Type nMask)121 inline bool getFlag( Type nBitField, Type nMask )
122 {
123     return (nBitField & nMask) != 0;
124 }
125 
126 /** Returns nSet, if at least one bit of nMask is set in nBitField, otherwise nUnset. */
127 template< typename ReturnType, typename Type >
getFlagValue(Type nBitField,Type nMask,ReturnType nSet,ReturnType nUnset)128 inline ReturnType getFlagValue( Type nBitField, Type nMask, ReturnType nSet, ReturnType nUnset )
129 {
130     return getFlag( nBitField, nMask ) ? nSet : nUnset;
131 }
132 
133 /** Extracts a value from a bit field.
134 
135     Returns the data fragment from nBitField, that starts at bit nStartBit
136     (0-based, bit 0 is rightmost) with the width of nBitCount. The returned
137     value will be right-aligned (normalized).
138     For instance: extractValue<T>(0x4321,8,4) returns 3 (value in bits 8-11).
139  */
140 template< typename ReturnType, typename Type >
extractValue(Type nBitField,sal_uInt8 nStartBit,sal_uInt8 nBitCount)141 inline ReturnType extractValue( Type nBitField, sal_uInt8 nStartBit, sal_uInt8 nBitCount )
142 {
143     sal_uInt64 nMask = 1; nMask <<= nBitCount; --nMask;
144     return static_cast< ReturnType >( nMask & (nBitField >> nStartBit) );
145 }
146 
147 // Write to bitfields ---------------------------------------------------------
148 
149 /** Sets or clears (according to bSet) all set bits of nMask in ornBitField. */
150 template< typename Type >
setFlag(Type & ornBitField,Type nMask,bool bSet=true)151 inline void setFlag( Type& ornBitField, Type nMask, bool bSet = true )
152 {
153     if( bSet ) ornBitField |= nMask; else ornBitField &= ~nMask;
154 }
155 
156 
157 /** Optional value, similar to ::boost::optional<>, with convenience accessors.
158  */
159 template< typename Type >
160 class OptValue
161 {
162 public:
OptValue()163                  OptValue() : maValue(), mbHasValue( false ) {}
OptValue(const Type & rValue)164     explicit     OptValue( const Type& rValue ) : maValue( rValue ), mbHasValue( true ) {}
OptValue(bool bHasValue,const Type & rValue)165     explicit     OptValue( bool bHasValue, const Type& rValue ) : maValue( rValue ), mbHasValue( bHasValue ) {}
166 
has() const167     bool         has() const { return mbHasValue; }
operator !() const168     bool         operator!() const { return !mbHasValue; }
differsFrom(const Type & rValue) const169     bool         differsFrom( const Type& rValue ) const { return mbHasValue && (maValue != rValue); }
170 
get() const171     const Type&  get() const { return maValue; }
get(const Type & rDefValue) const172     const Type&  get( const Type& rDefValue ) const { return mbHasValue ? maValue : rDefValue; }
173 
set(const Type & rValue)174     void         set( const Type& rValue ) { maValue = rValue; mbHasValue = true; }
use()175     Type&        use() { mbHasValue = true; return maValue; }
176 
operator =(const Type & rValue)177     OptValue&    operator=( const Type& rValue ) { set( rValue ); return *this; }
operator ==(const OptValue & rValue) const178     bool         operator==( const OptValue& rValue ) const {
179                              return ( ( !mbHasValue && rValue.mbHasValue == false ) ||
180                                  ( mbHasValue == rValue.mbHasValue && maValue == rValue.maValue ) );
181                  }
assignIfUsed(const OptValue & rValue)182     void         assignIfUsed( const OptValue& rValue ) { if( rValue.mbHasValue ) set( rValue.maValue ); }
183 
184 private:
185     Type                maValue;
186     bool                mbHasValue;
187 };
188 
189 
190 /** Provides platform independent functions to convert from or to little-endian
191     byte order, e.g. for reading data from or writing data to memory or a
192     binary stream.
193 
194     On big-endian platforms, the byte order in the passed values is swapped,
195     this can be used for converting big-endian to and from little-endian data.
196 
197     On little-endian platforms, the conversion functions are implemented empty,
198     thus compilers should completely optimize away the function call.
199  */
200 class ByteOrderConverter
201 {
202 public:
203 #ifdef OSL_BIGENDIAN
convertLittleEndian(sal_Int8 &)204     static void  convertLittleEndian( sal_Int8& ) {}     // present for usage in templates
convertLittleEndian(sal_uInt8 &)205     static void  convertLittleEndian( sal_uInt8& ) {}    // present for usage in templates
convertLittleEndian(char16_t & rnValue)206     static void  convertLittleEndian( char16_t& rnValue )   { swap2( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_Int16 & rnValue)207     static void  convertLittleEndian( sal_Int16& rnValue )  { swap2( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_uInt16 & rnValue)208     static void  convertLittleEndian( sal_uInt16& rnValue ) { swap2( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_Int32 & rnValue)209     static void  convertLittleEndian( sal_Int32& rnValue )  { swap4( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_uInt32 & rnValue)210     static void  convertLittleEndian( sal_uInt32& rnValue ) { swap4( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_Int64 & rnValue)211     static void  convertLittleEndian( sal_Int64& rnValue )  { swap8( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(sal_uInt64 & rnValue)212     static void  convertLittleEndian( sal_uInt64& rnValue ) { swap8( reinterpret_cast< sal_uInt8* >( &rnValue ) ); }
convertLittleEndian(float & rfValue)213     static void  convertLittleEndian( float& rfValue )      { swap4( reinterpret_cast< sal_uInt8* >( &rfValue ) ); }
convertLittleEndian(double & rfValue)214     static void  convertLittleEndian( double& rfValue )     { swap8( reinterpret_cast< sal_uInt8* >( &rfValue ) ); }
215 
216     template< typename Type >
217     inline static void  convertLittleEndianArray( Type* pnArray, size_t nElemCount );
218 
convertLittleEndianArray(sal_Int8 *,size_t)219     static void  convertLittleEndianArray( sal_Int8*, size_t ) {}
convertLittleEndianArray(sal_uInt8 *,size_t)220     static void  convertLittleEndianArray( sal_uInt8*, size_t ) {}
221 
222 #else
223     template< typename Type >
224     static void  convertLittleEndian( Type& ) {}
225 
226     template< typename Type >
227     static void  convertLittleEndianArray( Type*, size_t ) {}
228 
229 #endif
230 
231     /** Writes a value to memory, while converting it to little-endian.
232         @param pDstBuffer  The memory buffer to write the value to.
233         @param nValue  The value to be written to memory in little-endian.
234      */
235     template< typename Type >
236     inline static void  writeLittleEndian( void* pDstBuffer, Type nValue );
237 
238 #ifdef OSL_BIGENDIAN
239 private:
240     inline static void  swap2( sal_uInt8* pnData );
241     inline static void  swap4( sal_uInt8* pnData );
242     inline static void  swap8( sal_uInt8* pnData );
243 #endif
244 };
245 
246 
247 template< typename Type >
writeLittleEndian(void * pDstBuffer,Type nValue)248 inline void ByteOrderConverter::writeLittleEndian( void* pDstBuffer, Type nValue )
249 {
250     convertLittleEndian( nValue );
251     memcpy( pDstBuffer, &nValue, sizeof( Type ) );
252 }
253 
254 #ifdef OSL_BIGENDIAN
255 template< typename Type >
convertLittleEndianArray(Type * pnArray,size_t nElemCount)256 inline void ByteOrderConverter::convertLittleEndianArray( Type* pnArray, size_t nElemCount )
257 {
258     for( Type* pnArrayEnd = pnArray + nElemCount; pnArray != pnArrayEnd; ++pnArray )
259         convertLittleEndian( *pnArray );
260 }
261 
swap2(sal_uInt8 * pnData)262 inline void ByteOrderConverter::swap2( sal_uInt8* pnData )
263 {
264     ::std::swap( pnData[ 0 ], pnData[ 1 ] );
265 }
266 
swap4(sal_uInt8 * pnData)267 inline void ByteOrderConverter::swap4( sal_uInt8* pnData )
268 {
269     ::std::swap( pnData[ 0 ], pnData[ 3 ] );
270     ::std::swap( pnData[ 1 ], pnData[ 2 ] );
271 }
272 
swap8(sal_uInt8 * pnData)273 inline void ByteOrderConverter::swap8( sal_uInt8* pnData )
274 {
275     ::std::swap( pnData[ 0 ], pnData[ 7 ] );
276     ::std::swap( pnData[ 1 ], pnData[ 6 ] );
277     ::std::swap( pnData[ 2 ], pnData[ 5 ] );
278     ::std::swap( pnData[ 3 ], pnData[ 4 ] );
279 }
280 #endif
281 
282 
283 } // namespace oox
284 
285 #endif
286 
287 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
288