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 = NULL;
36 
37 U_CAPI UConverter* U_EXPORT2
u_getDefaultConverter(UErrorCode * status)38 u_getDefaultConverter(UErrorCode *status)
39 {
40     UConverter *converter = NULL;
41 
42     if (gDefaultConverter != NULL) {
43         icu::umtx_lock(NULL);
44 
45         /* need to check to make sure it wasn't taken out from under us */
46         if (gDefaultConverter != NULL) {
47             converter = gDefaultConverter;
48             gDefaultConverter = NULL;
49         }
50         icu::umtx_unlock(NULL);
51     }
52 
53     /* if the cache was empty, create a converter */
54     if(converter == NULL) {
55         converter = ucnv_open(NULL, status);
56         if(U_FAILURE(*status)) {
57             ucnv_close(converter);
58             converter = NULL;
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 == NULL) {
69         if (converter != NULL) {
70             ucnv_reset(converter);
71         }
72         ucnv_enableCleanup();
73         icu::umtx_lock(NULL);
74         if(gDefaultConverter == NULL) {
75             gDefaultConverter = converter;
76             converter = NULL;
77         }
78         icu::umtx_unlock(NULL);
79     }
80 
81     if(converter != NULL) {
82         ucnv_close(converter);
83     }
84 }
85 
86 U_CAPI void U_EXPORT2
u_flushDefaultConverter()87 u_flushDefaultConverter()
88 {
89     UConverter *converter = NULL;
90 
91     if (gDefaultConverter != NULL) {
92         icu::umtx_lock(NULL);
93 
94         /* need to check to make sure it wasn't taken out from under us */
95         if (gDefaultConverter != NULL) {
96             converter = gDefaultConverter;
97             gDefaultConverter = NULL;
98         }
99         icu::umtx_unlock(NULL);
100     }
101 
102     /* if the cache was populated, flush it */
103     if(converter != NULL) {
104          ucnv_close(converter);
105     }
106 }
107 
108 
109 /* conversions between char* and UChar* ------------------------------------- */
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 UChar*  U_EXPORT2
u_uastrncpy(UChar * ucs1,const char * s2,int32_t n)132 u_uastrncpy(UChar *ucs1,
133            const char *s2,
134            int32_t n)
135 {
136   UChar *target = ucs1;
137   UErrorCode err = U_ZERO_ERROR;
138   UConverter *cnv = u_getDefaultConverter(&err);
139   if(U_SUCCESS(err) && cnv != NULL) {
140     ucnv_reset(cnv);
141     ucnv_toUnicode(cnv,
142                    &target,
143                    ucs1+n,
144                    &s2,
145                    s2+u_astrnlen(s2, n),
146                    NULL,
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 UChar*  U_EXPORT2
u_uastrcpy(UChar * ucs1,const char * s2)164 u_uastrcpy(UChar *ucs1,
165           const char *s2 )
166 {
167   UErrorCode err = U_ZERO_ERROR;
168   UConverter *cnv = u_getDefaultConverter(&err);
169   if(U_SUCCESS(err) && cnv != NULL) {
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 UChar * ucs1,int32_t n)189 static int32_t u_ustrnlen(const UChar *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 UChar * ucs2,int32_t n)204 u_austrncpy(char *s1,
205         const UChar *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 != NULL) {
212     ucnv_reset(cnv);
213     ucnv_fromUnicode(cnv,
214                   &target,
215                   s1+n,
216                   &ucs2,
217                   ucs2+u_ustrnlen(ucs2, n),
218                   NULL,
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 UChar * ucs2)236 u_austrcpy(char *s1,
237          const UChar *ucs2 )
238 {
239   UErrorCode err = U_ZERO_ERROR;
240   UConverter *cnv = u_getDefaultConverter(&err);
241   if(U_SUCCESS(err) && cnv != NULL) {
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