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