ustr_cnv.cpp (6208B)
1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ******************************************************************************* 5 * 6 * Copyright (C) 1998-2014, International Business Machines 7 * Corporation and others. All Rights Reserved. 8 * 9 ******************************************************************************* 10 * file name: ustr_cnv.cpp 11 * encoding: UTF-8 12 * tab size: 8 (not used) 13 * indentation:4 14 * 15 * created on: 2004aug24 16 * created by: Markus W. Scherer 17 * 18 * Character conversion functions moved here from ustring.c 19 */ 20 21 #include "unicode/utypes.h" 22 23 #if !UCONFIG_NO_CONVERSION 24 25 #include "unicode/ustring.h" 26 #include "unicode/ucnv.h" 27 #include "cstring.h" 28 #include "cmemory.h" 29 #include "umutex.h" 30 #include "ustr_cnv.h" 31 #include "ucnv_bld.h" 32 33 /* mutexed access to a shared default converter ----------------------------- */ 34 35 static UConverter *gDefaultConverter = nullptr; 36 37 U_CAPI UConverter* U_EXPORT2 38 u_getDefaultConverter(UErrorCode *status) 39 { 40 UConverter *converter = nullptr; 41 42 if (gDefaultConverter != nullptr) { 43 icu::umtx_lock(nullptr); 44 45 /* need to check to make sure it wasn't taken out from under us */ 46 if (gDefaultConverter != nullptr) { 47 converter = gDefaultConverter; 48 gDefaultConverter = nullptr; 49 } 50 icu::umtx_unlock(nullptr); 51 } 52 53 /* if the cache was empty, create a converter */ 54 if(converter == nullptr) { 55 converter = ucnv_open(nullptr, status); 56 if(U_FAILURE(*status)) { 57 ucnv_close(converter); 58 converter = nullptr; 59 } 60 } 61 62 return converter; 63 } 64 65 U_CAPI void U_EXPORT2 66 u_releaseDefaultConverter(UConverter *converter) 67 { 68 if(gDefaultConverter == nullptr) { 69 if (converter != nullptr) { 70 ucnv_reset(converter); 71 } 72 ucnv_enableCleanup(); 73 icu::umtx_lock(nullptr); 74 if(gDefaultConverter == nullptr) { 75 gDefaultConverter = converter; 76 converter = nullptr; 77 } 78 icu::umtx_unlock(nullptr); 79 } 80 81 if(converter != nullptr) { 82 ucnv_close(converter); 83 } 84 } 85 86 U_CAPI void U_EXPORT2 87 u_flushDefaultConverter() 88 { 89 UConverter *converter = nullptr; 90 91 if (gDefaultConverter != nullptr) { 92 icu::umtx_lock(nullptr); 93 94 /* need to check to make sure it wasn't taken out from under us */ 95 if (gDefaultConverter != nullptr) { 96 converter = gDefaultConverter; 97 gDefaultConverter = nullptr; 98 } 99 icu::umtx_unlock(nullptr); 100 } 101 102 /* if the cache was populated, flush it */ 103 if(converter != nullptr) { 104 ucnv_close(converter); 105 } 106 } 107 108 109 /* conversions between char* and char16_t* ------------------------------------- */ 110 111 /* maximum string length for u_uastrcpy() and u_austrcpy() implementations */ 112 #define MAX_STRLEN 0x0FFFFFFF 113 114 /* 115 returns the minimum of (the length of the null-terminated string) and n. 116 */ 117 static int32_t u_astrnlen(const char *s1, int32_t n) 118 { 119 int32_t len = 0; 120 121 if (s1) 122 { 123 while (n-- && *(s1++)) 124 { 125 len++; 126 } 127 } 128 return len; 129 } 130 131 U_CAPI char16_t* U_EXPORT2 132 u_uastrncpy(char16_t *ucs1, 133 const char *s2, 134 int32_t n) 135 { 136 char16_t *target = ucs1; 137 UErrorCode err = U_ZERO_ERROR; 138 UConverter *cnv = u_getDefaultConverter(&err); 139 if(U_SUCCESS(err) && cnv != nullptr) { 140 ucnv_reset(cnv); 141 ucnv_toUnicode(cnv, 142 &target, 143 ucs1+n, 144 &s2, 145 s2+u_astrnlen(s2, n), 146 nullptr, 147 true, 148 &err); 149 ucnv_reset(cnv); /* be good citizens */ 150 u_releaseDefaultConverter(cnv); 151 if(U_FAILURE(err) && (err != U_BUFFER_OVERFLOW_ERROR) ) { 152 *ucs1 = 0; /* failure */ 153 } 154 if(target < (ucs1+n)) { /* U_BUFFER_OVERFLOW_ERROR isn't an err, just means no termination will happen. */ 155 *target = 0; /* terminate */ 156 } 157 } else { 158 *ucs1 = 0; 159 } 160 return ucs1; 161 } 162 163 U_CAPI char16_t* U_EXPORT2 164 u_uastrcpy(char16_t *ucs1, 165 const char *s2 ) 166 { 167 UErrorCode err = U_ZERO_ERROR; 168 UConverter *cnv = u_getDefaultConverter(&err); 169 if(U_SUCCESS(err) && cnv != nullptr) { 170 ucnv_toUChars(cnv, 171 ucs1, 172 MAX_STRLEN, 173 s2, 174 (int32_t)uprv_strlen(s2), 175 &err); 176 u_releaseDefaultConverter(cnv); 177 if(U_FAILURE(err)) { 178 *ucs1 = 0; 179 } 180 } else { 181 *ucs1 = 0; 182 } 183 return ucs1; 184 } 185 186 /* 187 returns the minimum of (the length of the null-terminated string) and n. 188 */ 189 static int32_t u_ustrnlen(const char16_t *ucs1, int32_t n) 190 { 191 int32_t len = 0; 192 193 if (ucs1) 194 { 195 while (n-- && *(ucs1++)) 196 { 197 len++; 198 } 199 } 200 return len; 201 } 202 203 U_CAPI char* U_EXPORT2 204 u_austrncpy(char *s1, 205 const char16_t *ucs2, 206 int32_t n) 207 { 208 char *target = s1; 209 UErrorCode err = U_ZERO_ERROR; 210 UConverter *cnv = u_getDefaultConverter(&err); 211 if(U_SUCCESS(err) && cnv != nullptr) { 212 ucnv_reset(cnv); 213 ucnv_fromUnicode(cnv, 214 &target, 215 s1+n, 216 &ucs2, 217 ucs2+u_ustrnlen(ucs2, n), 218 nullptr, 219 true, 220 &err); 221 ucnv_reset(cnv); /* be good citizens */ 222 u_releaseDefaultConverter(cnv); 223 if(U_FAILURE(err) && (err != U_BUFFER_OVERFLOW_ERROR) ) { 224 *s1 = 0; /* failure */ 225 } 226 if(target < (s1+n)) { /* U_BUFFER_OVERFLOW_ERROR isn't an err, just means no termination will happen. */ 227 *target = 0; /* terminate */ 228 } 229 } else { 230 *s1 = 0; 231 } 232 return s1; 233 } 234 235 U_CAPI char* U_EXPORT2 236 u_austrcpy(char *s1, 237 const char16_t *ucs2 ) 238 { 239 UErrorCode err = U_ZERO_ERROR; 240 UConverter *cnv = u_getDefaultConverter(&err); 241 if(U_SUCCESS(err) && cnv != nullptr) { 242 int32_t len = ucnv_fromUChars(cnv, 243 s1, 244 MAX_STRLEN, 245 ucs2, 246 -1, 247 &err); 248 u_releaseDefaultConverter(cnv); 249 s1[len] = 0; 250 } else { 251 *s1 = 0; 252 } 253 return s1; 254 } 255 256 #endif