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