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
u_getDefaultConverter(UErrorCode * status)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
u_releaseDefaultConverter(UConverter * converter)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
u_flushDefaultConverter()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 */
u_astrnlen(const char * s1,int32_t n)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
u_uastrncpy(char16_t * ucs1,const char * s2,int32_t n)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
u_uastrcpy(char16_t * ucs1,const char * s2)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 */
u_ustrnlen(const char16_t * ucs1,int32_t n)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
u_austrncpy(char * s1,const char16_t * ucs2,int32_t n)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
u_austrcpy(char * s1,const char16_t * ucs2)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
257