michael@0: /* michael@0: ******************************************************************************* michael@0: * michael@0: * Copyright (C) 1998-2013, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: * michael@0: ******************************************************************************* michael@0: * file name: ustr_cnv.c michael@0: * encoding: US-ASCII michael@0: * tab size: 8 (not used) michael@0: * indentation:4 michael@0: * michael@0: * created on: 2004aug24 michael@0: * created by: Markus W. Scherer michael@0: * michael@0: * Character conversion functions moved here from ustring.c michael@0: */ michael@0: michael@0: #include "unicode/utypes.h" michael@0: michael@0: #if !UCONFIG_NO_CONVERSION michael@0: michael@0: #include "unicode/ustring.h" michael@0: #include "unicode/ucnv.h" michael@0: #include "cstring.h" michael@0: #include "cmemory.h" michael@0: #include "cmutex.h" michael@0: #include "ustr_cnv.h" michael@0: michael@0: /* mutexed access to a shared default converter ----------------------------- */ michael@0: michael@0: static UConverter *gDefaultConverter = NULL; michael@0: michael@0: U_CAPI UConverter* U_EXPORT2 michael@0: u_getDefaultConverter(UErrorCode *status) michael@0: { michael@0: UConverter *converter = NULL; michael@0: michael@0: if (gDefaultConverter != NULL) { michael@0: umtx_lock(NULL); michael@0: michael@0: /* need to check to make sure it wasn't taken out from under us */ michael@0: if (gDefaultConverter != NULL) { michael@0: converter = gDefaultConverter; michael@0: gDefaultConverter = NULL; michael@0: } michael@0: umtx_unlock(NULL); michael@0: } michael@0: michael@0: /* if the cache was empty, create a converter */ michael@0: if(converter == NULL) { michael@0: converter = ucnv_open(NULL, status); michael@0: if(U_FAILURE(*status)) { michael@0: ucnv_close(converter); michael@0: converter = NULL; michael@0: } michael@0: } michael@0: michael@0: return converter; michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: u_releaseDefaultConverter(UConverter *converter) michael@0: { michael@0: if(gDefaultConverter == NULL) { michael@0: if (converter != NULL) { michael@0: ucnv_reset(converter); michael@0: } michael@0: umtx_lock(NULL); michael@0: michael@0: if(gDefaultConverter == NULL) { michael@0: gDefaultConverter = converter; michael@0: converter = NULL; michael@0: } michael@0: umtx_unlock(NULL); michael@0: } michael@0: michael@0: if(converter != NULL) { michael@0: ucnv_close(converter); michael@0: } michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: u_flushDefaultConverter() michael@0: { michael@0: UConverter *converter = NULL; michael@0: michael@0: if (gDefaultConverter != NULL) { michael@0: umtx_lock(NULL); michael@0: michael@0: /* need to check to make sure it wasn't taken out from under us */ michael@0: if (gDefaultConverter != NULL) { michael@0: converter = gDefaultConverter; michael@0: gDefaultConverter = NULL; michael@0: } michael@0: umtx_unlock(NULL); michael@0: } michael@0: michael@0: /* if the cache was populated, flush it */ michael@0: if(converter != NULL) { michael@0: ucnv_close(converter); michael@0: } michael@0: } michael@0: michael@0: michael@0: /* conversions between char* and UChar* ------------------------------------- */ michael@0: michael@0: /* maximum string length for u_uastrcpy() and u_austrcpy() implementations */ michael@0: #define MAX_STRLEN 0x0FFFFFFF michael@0: michael@0: /* michael@0: returns the minimum of (the length of the null-terminated string) and n. michael@0: */ michael@0: static int32_t u_astrnlen(const char *s1, int32_t n) michael@0: { michael@0: int32_t len = 0; michael@0: michael@0: if (s1) michael@0: { michael@0: while (n-- && *(s1++)) michael@0: { michael@0: len++; michael@0: } michael@0: } michael@0: return len; michael@0: } michael@0: michael@0: U_CAPI UChar* U_EXPORT2 michael@0: u_uastrncpy(UChar *ucs1, michael@0: const char *s2, michael@0: int32_t n) michael@0: { michael@0: UChar *target = ucs1; michael@0: UErrorCode err = U_ZERO_ERROR; michael@0: UConverter *cnv = u_getDefaultConverter(&err); michael@0: if(U_SUCCESS(err) && cnv != NULL) { michael@0: ucnv_reset(cnv); michael@0: ucnv_toUnicode(cnv, michael@0: &target, michael@0: ucs1+n, michael@0: &s2, michael@0: s2+u_astrnlen(s2, n), michael@0: NULL, michael@0: TRUE, michael@0: &err); michael@0: ucnv_reset(cnv); /* be good citizens */ michael@0: u_releaseDefaultConverter(cnv); michael@0: if(U_FAILURE(err) && (err != U_BUFFER_OVERFLOW_ERROR) ) { michael@0: *ucs1 = 0; /* failure */ michael@0: } michael@0: if(target < (ucs1+n)) { /* U_BUFFER_OVERFLOW_ERROR isn't an err, just means no termination will happen. */ michael@0: *target = 0; /* terminate */ michael@0: } michael@0: } else { michael@0: *ucs1 = 0; michael@0: } michael@0: return ucs1; michael@0: } michael@0: michael@0: U_CAPI UChar* U_EXPORT2 michael@0: u_uastrcpy(UChar *ucs1, michael@0: const char *s2 ) michael@0: { michael@0: UErrorCode err = U_ZERO_ERROR; michael@0: UConverter *cnv = u_getDefaultConverter(&err); michael@0: if(U_SUCCESS(err) && cnv != NULL) { michael@0: ucnv_toUChars(cnv, michael@0: ucs1, michael@0: MAX_STRLEN, michael@0: s2, michael@0: (int32_t)uprv_strlen(s2), michael@0: &err); michael@0: u_releaseDefaultConverter(cnv); michael@0: if(U_FAILURE(err)) { michael@0: *ucs1 = 0; michael@0: } michael@0: } else { michael@0: *ucs1 = 0; michael@0: } michael@0: return ucs1; michael@0: } michael@0: michael@0: /* michael@0: returns the minimum of (the length of the null-terminated string) and n. michael@0: */ michael@0: static int32_t u_ustrnlen(const UChar *ucs1, int32_t n) michael@0: { michael@0: int32_t len = 0; michael@0: michael@0: if (ucs1) michael@0: { michael@0: while (n-- && *(ucs1++)) michael@0: { michael@0: len++; michael@0: } michael@0: } michael@0: return len; michael@0: } michael@0: michael@0: U_CAPI char* U_EXPORT2 michael@0: u_austrncpy(char *s1, michael@0: const UChar *ucs2, michael@0: int32_t n) michael@0: { michael@0: char *target = s1; michael@0: UErrorCode err = U_ZERO_ERROR; michael@0: UConverter *cnv = u_getDefaultConverter(&err); michael@0: if(U_SUCCESS(err) && cnv != NULL) { michael@0: ucnv_reset(cnv); michael@0: ucnv_fromUnicode(cnv, michael@0: &target, michael@0: s1+n, michael@0: &ucs2, michael@0: ucs2+u_ustrnlen(ucs2, n), michael@0: NULL, michael@0: TRUE, michael@0: &err); michael@0: ucnv_reset(cnv); /* be good citizens */ michael@0: u_releaseDefaultConverter(cnv); michael@0: if(U_FAILURE(err) && (err != U_BUFFER_OVERFLOW_ERROR) ) { michael@0: *s1 = 0; /* failure */ michael@0: } michael@0: if(target < (s1+n)) { /* U_BUFFER_OVERFLOW_ERROR isn't an err, just means no termination will happen. */ michael@0: *target = 0; /* terminate */ michael@0: } michael@0: } else { michael@0: *s1 = 0; michael@0: } michael@0: return s1; michael@0: } michael@0: michael@0: U_CAPI char* U_EXPORT2 michael@0: u_austrcpy(char *s1, michael@0: const UChar *ucs2 ) michael@0: { michael@0: UErrorCode err = U_ZERO_ERROR; michael@0: UConverter *cnv = u_getDefaultConverter(&err); michael@0: if(U_SUCCESS(err) && cnv != NULL) { michael@0: int32_t len = ucnv_fromUChars(cnv, michael@0: s1, michael@0: MAX_STRLEN, michael@0: ucs2, michael@0: -1, michael@0: &err); michael@0: u_releaseDefaultConverter(cnv); michael@0: s1[len] = 0; michael@0: } else { michael@0: *s1 = 0; michael@0: } michael@0: return s1; michael@0: } michael@0: michael@0: #endif