ufmt_cmn.cpp (6584B)
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(char16_t 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(char16_t c, 57 int32_t radix) 58 { 59 int digitVal = ufmt_digitvalue(c); 60 61 return 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(char16_t *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 char16_t *left, *right, temp; 78 79 do { 80 digit = static_cast<uint32_t>(value % radix); 81 value = value / radix; 82 buffer[length++] = static_cast<char16_t>(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(char16_t *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 = reinterpret_cast<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 = static_cast<int32_t>(sizeof(void*)) - 1; i >= 0; i--) 118 #endif 119 { 120 uint8_t byteVal = ptrIdx[i]; 121 uint16_t firstNibble = static_cast<uint16_t>(byteVal >> 4); 122 uint16_t secondNibble = static_cast<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 char16_t *buffer, 138 int32_t *len, 139 int8_t radix) 140 { 141 const char16_t *limit; 142 int32_t count; 143 uint64_t result; 144 145 146 /* initialize 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 char16_t *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 /* initialize variables */ 179 count = 0; 180 offset = 0; 181 result.ptr = nullptr; 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 > static_cast<int32_t>(sizeof(void*) * NIBBLE_PER_BYTE)) { 197 offset = count - static_cast<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 = static_cast<uint8_t>(ufmt_digitvalue(buffer[count])); 213 214 if (count > offset) { 215 /* Get the second nibble of the byte when available */ 216 byte = static_cast<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 char16_t* 227 ufmt_defaultCPToUnicode(const char *s, int32_t sSize, 228 char16_t *target, int32_t tSize) 229 { 230 char16_t *alias; 231 UErrorCode status = U_ZERO_ERROR; 232 UConverter *defConverter = u_getDefaultConverter(&status); 233 234 if (U_FAILURE(status) || defConverter == nullptr) 235 return nullptr; 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 != nullptr) { 243 alias = target; 244 ucnv_toUnicode(defConverter, &alias, alias + tSize, &s, s + sSize - 1, 245 nullptr, true, &status); 246 247 248 /* add the null terminator */ 249 *alias = 0x0000; 250 } 251 252 u_releaseDefaultConverter(defConverter); 253 254 return target; 255 } 256 257 258 #endif