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