1/*
2*******************************************************************************
3*
4*   Copyright (C) 1998-2004, 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 "umutex.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
83/* conversions between char* and UChar* ------------------------------------- */
84
85/* maximum string length for u_uastrcpy() and u_austrcpy() implementations */
86#define MAX_STRLEN 0x0FFFFFFF
87
88/*
89 returns the minimum of (the length of the null-terminated string) and n.
90*/
91static int32_t u_astrnlen(const char *s1, int32_t n)
92{
93    int32_t len = 0;
94
95    if (s1)
96    {
97        while (n-- && *(s1++))
98        {
99            len++;
100        }
101    }
102    return len;
103}
104
105U_CAPI UChar*  U_EXPORT2
106u_uastrncpy(UChar *ucs1,
107           const char *s2,
108           int32_t n)
109{
110  UChar *target = ucs1;
111  UErrorCode err = U_ZERO_ERROR;
112  UConverter *cnv = u_getDefaultConverter(&err);
113  if(U_SUCCESS(err) && cnv != NULL) {
114    ucnv_reset(cnv);
115    ucnv_toUnicode(cnv,
116                   &target,
117                   ucs1+n,
118                   &s2,
119                   s2+u_astrnlen(s2, n),
120                   NULL,
121                   TRUE,
122                   &err);
123    ucnv_reset(cnv); /* be good citizens */
124    u_releaseDefaultConverter(cnv);
125    if(U_FAILURE(err) && (err != U_BUFFER_OVERFLOW_ERROR) ) {
126      *ucs1 = 0; /* failure */
127    }
128    if(target < (ucs1+n)) { /* U_BUFFER_OVERFLOW_ERROR isn't an err, just means no termination will happen. */
129      *target = 0;  /* terminate */
130    }
131  } else {
132    *ucs1 = 0;
133  }
134  return ucs1;
135}
136
137U_CAPI UChar*  U_EXPORT2
138u_uastrcpy(UChar *ucs1,
139          const char *s2 )
140{
141  UErrorCode err = U_ZERO_ERROR;
142  UConverter *cnv = u_getDefaultConverter(&err);
143  if(U_SUCCESS(err) && cnv != NULL) {
144    ucnv_toUChars(cnv,
145                    ucs1,
146                    MAX_STRLEN,
147                    s2,
148                    (int32_t)uprv_strlen(s2),
149                    &err);
150    u_releaseDefaultConverter(cnv);
151    if(U_FAILURE(err)) {
152      *ucs1 = 0;
153    }
154  } else {
155    *ucs1 = 0;
156  }
157  return ucs1;
158}
159
160/*
161 returns the minimum of (the length of the null-terminated string) and n.
162*/
163static int32_t u_ustrnlen(const UChar *ucs1, int32_t n)
164{
165    int32_t len = 0;
166
167    if (ucs1)
168    {
169        while (n-- && *(ucs1++))
170        {
171            len++;
172        }
173    }
174    return len;
175}
176
177U_CAPI char*  U_EXPORT2
178u_austrncpy(char *s1,
179        const UChar *ucs2,
180        int32_t n)
181{
182  char *target = s1;
183  UErrorCode err = U_ZERO_ERROR;
184  UConverter *cnv = u_getDefaultConverter(&err);
185  if(U_SUCCESS(err) && cnv != NULL) {
186    ucnv_reset(cnv);
187    ucnv_fromUnicode(cnv,
188                  &target,
189                  s1+n,
190                  &ucs2,
191                  ucs2+u_ustrnlen(ucs2, n),
192                  NULL,
193                  TRUE,
194                  &err);
195    ucnv_reset(cnv); /* be good citizens */
196    u_releaseDefaultConverter(cnv);
197    if(U_FAILURE(err) && (err != U_BUFFER_OVERFLOW_ERROR) ) {
198      *s1 = 0; /* failure */
199    }
200    if(target < (s1+n)) { /* U_BUFFER_OVERFLOW_ERROR isn't an err, just means no termination will happen. */
201      *target = 0;  /* terminate */
202    }
203  } else {
204    *s1 = 0;
205  }
206  return s1;
207}
208
209U_CAPI char*  U_EXPORT2
210u_austrcpy(char *s1,
211         const UChar *ucs2 )
212{
213  UErrorCode err = U_ZERO_ERROR;
214  UConverter *cnv = u_getDefaultConverter(&err);
215  if(U_SUCCESS(err) && cnv != NULL) {
216    int32_t len = ucnv_fromUChars(cnv,
217                  s1,
218                  MAX_STRLEN,
219                  ucs2,
220                  -1,
221                  &err);
222    u_releaseDefaultConverter(cnv);
223    s1[len] = 0;
224  } else {
225    *s1 = 0;
226  }
227  return s1;
228}
229
230#endif
231