1 // Copyright (C) 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: US-ASCII 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 32 /* mutexed access to a shared default converter ----------------------------- */ 33 34 static UConverter *gDefaultConverter = NULL; 35 36 U_CAPI UConverter* U_EXPORT2 37 u_getDefaultConverter(UErrorCode *status) 38 { 39 UConverter *converter = NULL; 40 41 if (gDefaultConverter != NULL) { 42 umtx_lock(NULL); 43 44 /* need to check to make sure it wasn't taken out from under us */ 45 if (gDefaultConverter != NULL) { 46 converter = gDefaultConverter; 47 gDefaultConverter = NULL; 48 } 49 umtx_unlock(NULL); 50 } 51 52 /* if the cache was empty, create a converter */ 53 if(converter == NULL) { 54 converter = ucnv_open(NULL, status); 55 if(U_FAILURE(*status)) { 56 ucnv_close(converter); 57 converter = NULL; 58 } 59 } 60 61 return converter; 62 } 63 64 U_CAPI void U_EXPORT2 65 u_releaseDefaultConverter(UConverter *converter) 66 { 67 if(gDefaultConverter == NULL) { 68 if (converter != NULL) { 69 ucnv_reset(converter); 70 } 71 umtx_lock(NULL); 72 73 if(gDefaultConverter == NULL) { 74 gDefaultConverter = converter; 75 converter = NULL; 76 } 77 umtx_unlock(NULL); 78 } 79 80 if(converter != NULL) { 81 ucnv_close(converter); 82 } 83 } 84 85 U_CAPI void U_EXPORT2 86 u_flushDefaultConverter() 87 { 88 UConverter *converter = NULL; 89 90 if (gDefaultConverter != NULL) { 91 umtx_lock(NULL); 92 93 /* need to check to make sure it wasn't taken out from under us */ 94 if (gDefaultConverter != NULL) { 95 converter = gDefaultConverter; 96 gDefaultConverter = NULL; 97 } 98 umtx_unlock(NULL); 99 } 100 101 /* if the cache was populated, flush it */ 102 if(converter != NULL) { 103 ucnv_close(converter); 104 } 105 } 106 107 108 /* conversions between char* and UChar* ------------------------------------- */ 109 110 /* maximum string length for u_uastrcpy() and u_austrcpy() implementations */ 111 #define MAX_STRLEN 0x0FFFFFFF 112 113 /* 114 returns the minimum of (the length of the null-terminated string) and n. 115 */ 116 static int32_t u_astrnlen(const char *s1, int32_t n) 117 { 118 int32_t len = 0; 119 120 if (s1) 121 { 122 while (n-- && *(s1++)) 123 { 124 len++; 125 } 126 } 127 return len; 128 } 129 130 U_CAPI UChar* U_EXPORT2 131 u_uastrncpy(UChar *ucs1, 132 const char *s2, 133 int32_t n) 134 { 135 UChar *target = ucs1; 136 UErrorCode err = U_ZERO_ERROR; 137 UConverter *cnv = u_getDefaultConverter(&err); 138 if(U_SUCCESS(err) && cnv != NULL) { 139 ucnv_reset(cnv); 140 ucnv_toUnicode(cnv, 141 &target, 142 ucs1+n, 143 &s2, 144 s2+u_astrnlen(s2, n), 145 NULL, 146 TRUE, 147 &err); 148 ucnv_reset(cnv); /* be good citizens */ 149 u_releaseDefaultConverter(cnv); 150 if(U_FAILURE(err) && (err != U_BUFFER_OVERFLOW_ERROR) ) { 151 *ucs1 = 0; /* failure */ 152 } 153 if(target < (ucs1+n)) { /* U_BUFFER_OVERFLOW_ERROR isn't an err, just means no termination will happen. */ 154 *target = 0; /* terminate */ 155 } 156 } else { 157 *ucs1 = 0; 158 } 159 return ucs1; 160 } 161 162 U_CAPI UChar* U_EXPORT2 163 u_uastrcpy(UChar *ucs1, 164 const char *s2 ) 165 { 166 UErrorCode err = U_ZERO_ERROR; 167 UConverter *cnv = u_getDefaultConverter(&err); 168 if(U_SUCCESS(err) && cnv != NULL) { 169 ucnv_toUChars(cnv, 170 ucs1, 171 MAX_STRLEN, 172 s2, 173 (int32_t)uprv_strlen(s2), 174 &err); 175 u_releaseDefaultConverter(cnv); 176 if(U_FAILURE(err)) { 177 *ucs1 = 0; 178 } 179 } else { 180 *ucs1 = 0; 181 } 182 return ucs1; 183 } 184 185 /* 186 returns the minimum of (the length of the null-terminated string) and n. 187 */ 188 static int32_t u_ustrnlen(const UChar *ucs1, int32_t n) 189 { 190 int32_t len = 0; 191 192 if (ucs1) 193 { 194 while (n-- && *(ucs1++)) 195 { 196 len++; 197 } 198 } 199 return len; 200 } 201 202 U_CAPI char* U_EXPORT2 203 u_austrncpy(char *s1, 204 const UChar *ucs2, 205 int32_t n) 206 { 207 char *target = s1; 208 UErrorCode err = U_ZERO_ERROR; 209 UConverter *cnv = u_getDefaultConverter(&err); 210 if(U_SUCCESS(err) && cnv != NULL) { 211 ucnv_reset(cnv); 212 ucnv_fromUnicode(cnv, 213 &target, 214 s1+n, 215 &ucs2, 216 ucs2+u_ustrnlen(ucs2, n), 217 NULL, 218 TRUE, 219 &err); 220 ucnv_reset(cnv); /* be good citizens */ 221 u_releaseDefaultConverter(cnv); 222 if(U_FAILURE(err) && (err != U_BUFFER_OVERFLOW_ERROR) ) { 223 *s1 = 0; /* failure */ 224 } 225 if(target < (s1+n)) { /* U_BUFFER_OVERFLOW_ERROR isn't an err, just means no termination will happen. */ 226 *target = 0; /* terminate */ 227 } 228 } else { 229 *s1 = 0; 230 } 231 return s1; 232 } 233 234 U_CAPI char* U_EXPORT2 235 u_austrcpy(char *s1, 236 const UChar *ucs2 ) 237 { 238 UErrorCode err = U_ZERO_ERROR; 239 UConverter *cnv = u_getDefaultConverter(&err); 240 if(U_SUCCESS(err) && cnv != NULL) { 241 int32_t len = ucnv_fromUChars(cnv, 242 s1, 243 MAX_STRLEN, 244 ucs2, 245 -1, 246 &err); 247 u_releaseDefaultConverter(cnv); 248 s1[len] = 0; 249 } else { 250 *s1 = 0; 251 } 252 return s1; 253 } 254 255 #endif 256