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 #if defined(_MSC_VER) && (_MSC_VER >= 1400) 24 #pragma warning(disable:4738) // storing 32-bit float result in memory, possible loss of performance 25 #endif 26 27 #include <rtl/memory.h> 28 #include <osl/interlck.h> 29 #include <rtl/alloc.h> 30 #include <osl/diagnose.h> 31 #include <rtl/tencinfo.h> 32 33 #include "strimp.h" 34 #include "surrogates.h" 35 #include <rtl/string.h> 36 37 #include "rtl/math.h" 38 #include "rtl/tencinfo.h" 39 40 /* ======================================================================= */ 41 42 /* static data to be referenced by all empty strings 43 * the refCount is predefined to 1 and must never become 0 ! 44 */ 45 static rtl_String const aImplEmpty_rtl_String = 46 { 47 SAL_STRING_STATIC_FLAG|1, 48 /* sal_Int32 refCount; */ 49 0, /* sal_Int32 length; */ 50 { 0 } /* sal_Char buffer[1]; */ 51 }; 52 53 /* ======================================================================= */ 54 55 #define IMPL_RTL_STRCODE sal_Char 56 #define IMPL_RTL_USTRCODE( c ) ((unsigned char)c) 57 #define IMPL_RTL_STRNAME( n ) rtl_str_ ## n 58 59 #define IMPL_RTL_STRINGNAME( n ) rtl_string_ ## n 60 #define IMPL_RTL_STRINGDATA rtl_String 61 #define IMPL_RTL_EMPTYSTRING aImplEmpty_rtl_String 62 63 /* ======================================================================= */ 64 65 /* Include String/UString template code */ 66 67 #include "strtmpl.c" 68 69 sal_Int32 SAL_CALL rtl_str_valueOfFloat(sal_Char * pStr, float f) 70 { 71 rtl_String * pResult = NULL; 72 sal_Int32 nLen; 73 rtl_math_doubleToString( 74 &pResult, 0, 0, f, rtl_math_StringFormat_G, 75 RTL_STR_MAX_VALUEOFFLOAT - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', 0, 0, 76 sal_True); 77 nLen = pResult->length; 78 OSL_ASSERT(nLen < RTL_STR_MAX_VALUEOFFLOAT); 79 rtl_copyMemory(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Char)); 80 rtl_string_release(pResult); 81 return nLen; 82 } 83 84 sal_Int32 SAL_CALL rtl_str_valueOfDouble(sal_Char * pStr, double d) 85 { 86 rtl_String * pResult = NULL; 87 sal_Int32 nLen; 88 rtl_math_doubleToString( 89 &pResult, 0, 0, d, rtl_math_StringFormat_G, 90 RTL_STR_MAX_VALUEOFDOUBLE - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', 0, 91 0, sal_True); 92 nLen = pResult->length; 93 OSL_ASSERT(nLen < RTL_STR_MAX_VALUEOFDOUBLE); 94 rtl_copyMemory(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Char)); 95 rtl_string_release(pResult); 96 return nLen; 97 } 98 99 float SAL_CALL rtl_str_toFloat(sal_Char const * pStr) 100 { 101 return (float) rtl_math_stringToDouble(pStr, pStr + rtl_str_getLength(pStr), 102 '.', 0, 0, 0); 103 } 104 105 double SAL_CALL rtl_str_toDouble(sal_Char const * pStr) 106 { 107 return rtl_math_stringToDouble(pStr, pStr + rtl_str_getLength(pStr), '.', 0, 108 0, 0); 109 } 110 111 /* ======================================================================= */ 112 113 static int rtl_ImplGetFastUTF8ByteLen( const sal_Unicode* pStr, sal_Int32 nLen ) 114 { 115 int n; 116 sal_Unicode c; 117 sal_uInt32 nUCS4Char; 118 const sal_Unicode* pEndStr; 119 120 n = 0; 121 pEndStr = pStr+nLen; 122 while ( pStr < pEndStr ) 123 { 124 c = *pStr; 125 126 if ( c < 0x80 ) 127 n++; 128 else if ( c < 0x800 ) 129 n += 2; 130 else 131 { 132 if ( !SAL_RTL_IS_HIGH_SURROGATE(c) ) 133 n += 3; 134 else 135 { 136 nUCS4Char = c; 137 138 if ( pStr+1 < pEndStr ) 139 { 140 c = *(pStr+1); 141 if ( SAL_RTL_IS_LOW_SURROGATE(c) ) 142 { 143 nUCS4Char = SAL_RTL_COMBINE_SURROGATES(nUCS4Char, c); 144 pStr++; 145 } 146 } 147 148 if ( nUCS4Char < 0x10000 ) 149 n += 3; 150 else if ( nUCS4Char < 0x200000 ) 151 n += 4; 152 else if ( nUCS4Char < 0x4000000 ) 153 n += 5; 154 else 155 n += 6; 156 } 157 } 158 159 pStr++; 160 } 161 162 return n; 163 } 164 165 /* ----------------------------------------------------------------------- */ 166 167 sal_Bool SAL_CALL rtl_impl_convertUStringToString(rtl_String ** pTarget, 168 sal_Unicode const * pSource, 169 sal_Int32 nLength, 170 rtl_TextEncoding nEncoding, 171 sal_uInt32 nFlags, 172 sal_Bool bCheckErrors) 173 { 174 OSL_ASSERT(pTarget != NULL 175 && (pSource != NULL || nLength == 0) 176 && nLength >= 0 177 && rtl_isOctetTextEncoding(nEncoding)); 178 179 if ( !nLength ) 180 rtl_string_new( pTarget ); 181 else 182 { 183 rtl_String* pTemp; 184 rtl_UnicodeToTextConverter hConverter; 185 sal_uInt32 nInfo; 186 sal_Size nSrcChars; 187 sal_Size nDestBytes; 188 sal_Size nNewLen; 189 sal_Size nNotConvertedChars; 190 sal_Size nMaxCharLen; 191 192 /* Optimization for UTF-8 - we try to calculate the exact length */ 193 /* For all other encoding we try an good estimation */ 194 if ( nEncoding == RTL_TEXTENCODING_UTF8 ) 195 { 196 nNewLen = rtl_ImplGetFastUTF8ByteLen( pSource, nLength ); 197 /* Includes the string only ASCII, then we could copy 198 the buffer faster */ 199 if ( nNewLen == (sal_Size)nLength ) 200 { 201 IMPL_RTL_STRCODE* pBuffer; 202 if ( *pTarget ) 203 IMPL_RTL_STRINGNAME( release )( *pTarget ); 204 *pTarget = IMPL_RTL_STRINGNAME( ImplAlloc )( nLength ); 205 OSL_ASSERT(*pTarget != NULL); 206 pBuffer = (*pTarget)->buffer; 207 do 208 { 209 /* Check ASCII range */ 210 OSL_ENSURE( *pSource <= 127, 211 "rtl_uString2String() - UTF8 test is encoding is wrong" ); 212 213 *pBuffer = (IMPL_RTL_STRCODE)(unsigned char)*pSource; 214 pBuffer++; 215 pSource++; 216 nLength--; 217 } 218 while ( nLength ); 219 return sal_True; 220 } 221 222 nMaxCharLen = 4; 223 } 224 else 225 { 226 rtl_TextEncodingInfo aTextEncInfo; 227 aTextEncInfo.StructSize = sizeof( aTextEncInfo ); 228 if ( !rtl_getTextEncodingInfo( nEncoding, &aTextEncInfo ) ) 229 { 230 aTextEncInfo.AverageCharSize = 1; 231 aTextEncInfo.MaximumCharSize = 8; 232 } 233 234 nNewLen = nLength*aTextEncInfo.AverageCharSize; 235 nMaxCharLen = aTextEncInfo.MaximumCharSize; 236 } 237 238 nFlags |= RTL_UNICODETOTEXT_FLAGS_FLUSH; 239 hConverter = rtl_createUnicodeToTextConverter( nEncoding ); 240 241 for (;;) 242 { 243 pTemp = IMPL_RTL_STRINGNAME( ImplAlloc )( nNewLen ); 244 OSL_ASSERT(pTemp != NULL); 245 nDestBytes = rtl_convertUnicodeToText( hConverter, 0, 246 pSource, nLength, 247 pTemp->buffer, nNewLen, 248 nFlags, 249 &nInfo, &nSrcChars ); 250 if (bCheckErrors && (nInfo & RTL_UNICODETOTEXT_INFO_ERROR) != 0) 251 { 252 rtl_freeMemory(pTemp); 253 rtl_destroyUnicodeToTextConverter(hConverter); 254 return sal_False; 255 } 256 257 if ((nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL) == 0) 258 break; 259 260 /* Buffer not big enough, try again with enough space */ 261 rtl_freeMemory( pTemp ); 262 263 /* Try with the max. count of characters with 264 additional overhead for replacing functionality */ 265 nNotConvertedChars = nLength-nSrcChars; 266 nNewLen = nDestBytes+(nNotConvertedChars*nMaxCharLen)+nNotConvertedChars+4; 267 } 268 269 /* Set the buffer to the correct size or is there to 270 much overhead, reallocate to the correct size */ 271 if ( nNewLen > nDestBytes+8 ) 272 { 273 rtl_String* pTemp2 = IMPL_RTL_STRINGNAME( ImplAlloc )( nDestBytes ); 274 OSL_ASSERT(pTemp2 != NULL); 275 rtl_str_ImplCopy( pTemp2->buffer, pTemp->buffer, nDestBytes ); 276 rtl_freeMemory( pTemp ); 277 pTemp = pTemp2; 278 } 279 else 280 { 281 pTemp->length = nDestBytes; 282 pTemp->buffer[nDestBytes] = 0; 283 } 284 285 rtl_destroyUnicodeToTextConverter( hConverter ); 286 if ( *pTarget ) 287 IMPL_RTL_STRINGNAME( release )( *pTarget ); 288 *pTarget = pTemp; 289 290 /* Results the conversion in an empty buffer - 291 create an empty string */ 292 if ( pTemp && !nDestBytes ) 293 rtl_string_new( pTarget ); 294 } 295 return sal_True; 296 } 297 298 void SAL_CALL rtl_uString2String( rtl_String** ppThis, 299 const sal_Unicode* pUStr, 300 sal_Int32 nULen, 301 rtl_TextEncoding eTextEncoding, 302 sal_uInt32 nCvtFlags ) 303 { 304 rtl_impl_convertUStringToString(ppThis, pUStr, nULen, eTextEncoding, 305 nCvtFlags, sal_False); 306 } 307 308 sal_Bool SAL_CALL rtl_convertUStringToString(rtl_String ** pTarget, 309 sal_Unicode const * pSource, 310 sal_Int32 nLength, 311 rtl_TextEncoding nEncoding, 312 sal_uInt32 nFlags) 313 { 314 return rtl_impl_convertUStringToString(pTarget, pSource, nLength, nEncoding, 315 nFlags, sal_True); 316 } 317