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