Home | History | Annotate | Download | only in io
      1 /*
      2 ******************************************************************************
      3 *
      4 *   Copyright (C) 1998-2014, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 ******************************************************************************
      8 *
      9 * File ufmt_cmn.c
     10 *
     11 * Modification History:
     12 *
     13 *   Date        Name        Description
     14 *   12/02/98    stephen     Creation.
     15 *   03/12/99    stephen     Modified for new C API.
     16 *   03/15/99    stephen     Added defaultCPToUnicode, unicodeToDefaultCP
     17 *   07/19/99    stephen     Fixed bug in defaultCPToUnicode
     18 ******************************************************************************
     19 */
     20 
     21 #include "cstring.h"
     22 #include "cmemory.h"
     23 #include "ufmt_cmn.h"
     24 #include "unicode/uchar.h"
     25 #include "unicode/ucnv.h"
     26 #include "ustr_cnv.h"
     27 
     28 #if !UCONFIG_NO_CONVERSION
     29 
     30 
     31 #define DIGIT_0     0x0030
     32 #define DIGIT_9     0x0039
     33 #define LOWERCASE_A 0x0061
     34 #define UPPERCASE_A 0x0041
     35 #define LOWERCASE_Z 0x007A
     36 #define UPPERCASE_Z 0x005A
     37 
     38 int
     39 ufmt_digitvalue(UChar c)
     40 {
     41     if( ((c>=DIGIT_0)&&(c<=DIGIT_9)) ||
     42         ((c>=LOWERCASE_A)&&(c<=LOWERCASE_Z)) ||
     43         ((c>=UPPERCASE_A)&&(c<=UPPERCASE_Z))  )
     44     {
     45       return c - DIGIT_0 - (c >= 0x0041 ? (c >= 0x0061 ? 39 : 7) : 0);
     46     }
     47     else
     48     {
     49       return -1;
     50     }
     51 }
     52 
     53 UBool
     54 ufmt_isdigit(UChar     c,
     55              int32_t     radix)
     56 {
     57     int digitVal = ufmt_digitvalue(c);
     58 
     59     return (UBool)(digitVal < radix && digitVal >= 0);
     60 }
     61 
     62 #define TO_UC_DIGIT(a) a <= 9 ? (DIGIT_0 + a) : (0x0037 + a)
     63 #define TO_LC_DIGIT(a) a <= 9 ? (DIGIT_0 + a) : (0x0057 + a)
     64 
     65 void
     66 ufmt_64tou(UChar     *buffer,
     67           int32_t   *len,
     68           uint64_t  value,
     69           uint8_t  radix,
     70           UBool     uselower,
     71           int32_t   minDigits)
     72 {
     73     int32_t  length = 0;
     74     uint32_t digit;
     75     UChar    *left, *right, temp;
     76 
     77     do {
     78         digit = (uint32_t)(value % radix);
     79         value = value / radix;
     80         buffer[length++] = (UChar)(uselower ? TO_LC_DIGIT(digit)
     81             : TO_UC_DIGIT(digit));
     82     } while(value);
     83 
     84     /* pad with zeroes to make it minDigits long */
     85     if(minDigits != -1 && length < minDigits) {
     86         while(length < minDigits && length < *len)
     87             buffer[length++] = DIGIT_0;  /*zero padding */
     88     }
     89 
     90     /* reverse the buffer */
     91     left     = buffer;
     92     right = buffer + length;
     93     while(left < --right) {
     94         temp     = *left;
     95         *left++     = *right;
     96         *right     = temp;
     97     }
     98 
     99     *len = length;
    100 }
    101 
    102 void
    103 ufmt_ptou(UChar    *buffer,
    104           int32_t   *len,
    105           void      *value,
    106           UBool     uselower)
    107 {
    108     int32_t i;
    109     int32_t length = 0;
    110     uint8_t *ptrIdx = (uint8_t *)&value;
    111 
    112 #if U_IS_BIG_ENDIAN
    113     for (i = 0; i < (int32_t)sizeof(void *); i++)
    114 #else
    115     for (i = (int32_t)sizeof(void *)-1; i >= 0 ; i--)
    116 #endif
    117     {
    118         uint8_t byteVal = ptrIdx[i];
    119         uint16_t firstNibble = (uint16_t)(byteVal>>4);
    120         uint16_t secondNibble = (uint16_t)(byteVal&0xF);
    121         if (uselower) {
    122             buffer[length++]=TO_LC_DIGIT(firstNibble);
    123             buffer[length++]=TO_LC_DIGIT(secondNibble);
    124         }
    125         else {
    126             buffer[length++]=TO_UC_DIGIT(firstNibble);
    127             buffer[length++]=TO_UC_DIGIT(secondNibble);
    128         }
    129     }
    130 
    131     *len = length;
    132 }
    133 
    134 int64_t
    135 ufmt_uto64(const UChar     *buffer,
    136           int32_t     *len,
    137           int8_t     radix)
    138 {
    139     const UChar     *limit;
    140     int32_t         count;
    141     int64_t        result;
    142 
    143 
    144     /* intialize parameters */
    145     limit     = buffer + *len;
    146     count     = 0;
    147     result    = 0;
    148 
    149     /* iterate through buffer */
    150     while(ufmt_isdigit(*buffer, radix) && buffer < limit) {
    151 
    152         /* read the next digit */
    153         result *= radix;
    154         result += ufmt_digitvalue(*buffer++);
    155 
    156         /* increment our count */
    157         ++count;
    158     }
    159 
    160     *len = count;
    161     return result;
    162 }
    163 
    164 #define NIBBLE_PER_BYTE 2
    165 void *
    166 ufmt_utop(const UChar     *buffer,
    167           int32_t     *len)
    168 {
    169     int32_t count, resultIdx, incVal, offset;
    170     /* This union allows the pointer to be written as an array. */
    171     union {
    172         void *ptr;
    173         uint8_t bytes[sizeof(void*)];
    174     } result;
    175 
    176     /* intialize variables */
    177     count      = 0;
    178     offset     = 0;
    179     result.ptr = NULL;
    180 
    181     /* Skip the leading zeros */
    182     while(buffer[count] == DIGIT_0 || u_isspace(buffer[count])) {
    183         count++;
    184         offset++;
    185     }
    186 
    187     /* iterate through buffer, stop when you hit the end */
    188     while(ufmt_isdigit(buffer[count], 16) && count < *len) {
    189         /* increment the count consumed */
    190         ++count;
    191     }
    192 
    193     /* detect overflow */
    194     if (count - offset > (int32_t)(sizeof(void*)*NIBBLE_PER_BYTE)) {
    195         offset = count - (int32_t)(sizeof(void*)*NIBBLE_PER_BYTE);
    196     }
    197 
    198     /* Initialize the direction of the input */
    199 #if U_IS_BIG_ENDIAN
    200     incVal = -1;
    201     resultIdx = (int32_t)(sizeof(void*) - 1);
    202 #else
    203     incVal = 1;
    204     resultIdx = 0;
    205 #endif
    206     /* Write how much was consumed. */
    207     *len = count;
    208     while(--count >= offset) {
    209         /* Get the first nibble of the byte */
    210         uint8_t byte = (uint8_t)ufmt_digitvalue(buffer[count]);
    211 
    212         if (count > offset) {
    213             /* Get the second nibble of the byte when available */
    214             byte = (uint8_t)(byte + (ufmt_digitvalue(buffer[--count]) << 4));
    215         }
    216         /* Write the byte into the array */
    217         result.bytes[resultIdx] = byte;
    218         resultIdx += incVal;
    219     }
    220 
    221     return result.ptr;
    222 }
    223 
    224 UChar*
    225 ufmt_defaultCPToUnicode(const char *s, int32_t sSize,
    226                         UChar *target, int32_t tSize)
    227 {
    228     UChar *alias;
    229     UErrorCode status = U_ZERO_ERROR;
    230     UConverter *defConverter = u_getDefaultConverter(&status);
    231 
    232     if(U_FAILURE(status) || defConverter == 0)
    233         return 0;
    234 
    235     if(sSize <= 0) {
    236         sSize = uprv_strlen(s) + 1;
    237     }
    238 
    239     /* perform the conversion in one swoop */
    240     if(target != 0) {
    241 
    242         alias = target;
    243         ucnv_toUnicode(defConverter, &alias, alias + tSize, &s, s + sSize - 1,
    244             NULL, TRUE, &status);
    245 
    246 
    247         /* add the null terminator */
    248         *alias = 0x0000;
    249     }
    250 
    251     u_releaseDefaultConverter(defConverter);
    252 
    253     return target;
    254 }
    255 
    256 
    257 #endif
    258