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
ufmt_digitvalue(UChar c)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
ufmt_isdigit(UChar c,int32_t radix)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
ufmt_64tou(UChar * buffer,int32_t * len,uint64_t value,uint8_t radix,UBool uselower,int32_t minDigits)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
ufmt_ptou(UChar * buffer,int32_t * len,void * value,UBool uselower)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
ufmt_uto64(const UChar * buffer,int32_t * len,int8_t radix)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 *
ufmt_utop(const UChar * buffer,int32_t * len)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*
ufmt_defaultCPToUnicode(const char * s,int32_t sSize,UChar * target,int32_t tSize)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