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