Home | History | Annotate | Download | only in common
      1 /*
      2 *******************************************************************************
      3 *
      4 *   Copyright (C) 1998-2010, 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 
     32 static UConverter *gDefaultConverter = NULL;
     33 
     34 U_CAPI UConverter* U_EXPORT2
     35 u_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 
     62 U_CAPI void U_EXPORT2
     63 u_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 U_CAPI void U_EXPORT2
     84 u_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 */
    114 static 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 
    128 U_CAPI UChar*  U_EXPORT2
    129 u_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 
    160 U_CAPI UChar*  U_EXPORT2
    161 u_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 */
    186 static 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 
    200 U_CAPI char*  U_EXPORT2
    201 u_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 
    232 U_CAPI char*  U_EXPORT2
    233 u_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