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