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