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