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
35int
36ufmt_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
50UBool
51ufmt_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
62void
63ufmt_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
99void
100ufmt_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
131int64_t
132ufmt_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
162void *
163ufmt_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
221UChar*
222ufmt_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