michael@0: /* michael@0: ****************************************************************************** michael@0: * michael@0: * Copyright (C) 1998-2006, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: * michael@0: ****************************************************************************** michael@0: * michael@0: * File ufmt_cmn.c michael@0: * michael@0: * Modification History: michael@0: * michael@0: * Date Name Description michael@0: * 12/02/98 stephen Creation. michael@0: * 03/12/99 stephen Modified for new C API. michael@0: * 03/15/99 stephen Added defaultCPToUnicode, unicodeToDefaultCP michael@0: * 07/19/99 stephen Fixed bug in defaultCPToUnicode michael@0: ****************************************************************************** michael@0: */ michael@0: michael@0: #include "cstring.h" michael@0: #include "cmemory.h" michael@0: #include "ufmt_cmn.h" michael@0: #include "unicode/uchar.h" michael@0: #include "unicode/ucnv.h" michael@0: #include "ustr_cnv.h" michael@0: michael@0: #define DIGIT_0 0x0030 michael@0: #define DIGIT_9 0x0039 michael@0: #define LOWERCASE_A 0x0061 michael@0: #define UPPERCASE_A 0x0041 michael@0: #define LOWERCASE_Z 0x007A michael@0: #define UPPERCASE_Z 0x005A michael@0: michael@0: int michael@0: ufmt_digitvalue(UChar c) michael@0: { michael@0: if( ((c>=DIGIT_0)&&(c<=DIGIT_9)) || michael@0: ((c>=LOWERCASE_A)&&(c<=LOWERCASE_Z)) || michael@0: ((c>=UPPERCASE_A)&&(c<=UPPERCASE_Z)) ) michael@0: { michael@0: return c - DIGIT_0 - (c >= 0x0041 ? (c >= 0x0061 ? 39 : 7) : 0); michael@0: } michael@0: else michael@0: { michael@0: return -1; michael@0: } michael@0: } michael@0: michael@0: UBool michael@0: ufmt_isdigit(UChar c, michael@0: int32_t radix) michael@0: { michael@0: int digitVal = ufmt_digitvalue(c); michael@0: michael@0: return (UBool)(digitVal < radix && digitVal >= 0); michael@0: } michael@0: michael@0: #define TO_UC_DIGIT(a) a <= 9 ? (DIGIT_0 + a) : (0x0037 + a) michael@0: #define TO_LC_DIGIT(a) a <= 9 ? (DIGIT_0 + a) : (0x0057 + a) michael@0: michael@0: void michael@0: ufmt_64tou(UChar *buffer, michael@0: int32_t *len, michael@0: uint64_t value, michael@0: uint8_t radix, michael@0: UBool uselower, michael@0: int32_t minDigits) michael@0: { michael@0: int32_t length = 0; michael@0: uint32_t digit; michael@0: UChar *left, *right, temp; michael@0: michael@0: do { michael@0: digit = (uint32_t)(value % radix); michael@0: value = value / radix; michael@0: buffer[length++] = (UChar)(uselower ? TO_LC_DIGIT(digit) michael@0: : TO_UC_DIGIT(digit)); michael@0: } while(value); michael@0: michael@0: /* pad with zeroes to make it minDigits long */ michael@0: if(minDigits != -1 && length < minDigits) { michael@0: while(length < minDigits && length < *len) michael@0: buffer[length++] = DIGIT_0; /*zero padding */ michael@0: } michael@0: michael@0: /* reverse the buffer */ michael@0: left = buffer; michael@0: right = buffer + length; michael@0: while(left < --right) { michael@0: temp = *left; michael@0: *left++ = *right; michael@0: *right = temp; michael@0: } michael@0: michael@0: *len = length; michael@0: } michael@0: michael@0: void michael@0: ufmt_ptou(UChar *buffer, michael@0: int32_t *len, michael@0: void *value, michael@0: UBool uselower) michael@0: { michael@0: int32_t i; michael@0: int32_t length = 0; michael@0: uint8_t *ptrIdx = (uint8_t *)&value; michael@0: michael@0: #if U_IS_BIG_ENDIAN michael@0: for (i = 0; i < (int32_t)sizeof(void *); i++) michael@0: #else michael@0: for (i = (int32_t)sizeof(void *)-1; i >= 0 ; i--) michael@0: #endif michael@0: { michael@0: uint8_t byteVal = ptrIdx[i]; michael@0: uint16_t firstNibble = (uint16_t)(byteVal>>4); michael@0: uint16_t secondNibble = (uint16_t)(byteVal&0xF); michael@0: if (uselower) { michael@0: buffer[length++]=TO_LC_DIGIT(firstNibble); michael@0: buffer[length++]=TO_LC_DIGIT(secondNibble); michael@0: } michael@0: else { michael@0: buffer[length++]=TO_UC_DIGIT(firstNibble); michael@0: buffer[length++]=TO_UC_DIGIT(secondNibble); michael@0: } michael@0: } michael@0: michael@0: *len = length; michael@0: } michael@0: michael@0: int64_t michael@0: ufmt_uto64(const UChar *buffer, michael@0: int32_t *len, michael@0: int8_t radix) michael@0: { michael@0: const UChar *limit; michael@0: int32_t count; michael@0: int64_t result; michael@0: michael@0: michael@0: /* intialize parameters */ michael@0: limit = buffer + *len; michael@0: count = 0; michael@0: result = 0; michael@0: michael@0: /* iterate through buffer */ michael@0: while(ufmt_isdigit(*buffer, radix) && buffer < limit) { michael@0: michael@0: /* read the next digit */ michael@0: result *= radix; michael@0: result += ufmt_digitvalue(*buffer++); michael@0: michael@0: /* increment our count */ michael@0: ++count; michael@0: } michael@0: michael@0: *len = count; michael@0: return result; michael@0: } michael@0: michael@0: #define NIBBLE_PER_BYTE 2 michael@0: void * michael@0: ufmt_utop(const UChar *buffer, michael@0: int32_t *len) michael@0: { michael@0: int32_t count, resultIdx, incVal, offset; michael@0: /* This union allows the pointer to be written as an array. */ michael@0: union { michael@0: void *ptr; michael@0: uint8_t bytes[sizeof(void*)]; michael@0: } result; michael@0: michael@0: /* intialize variables */ michael@0: count = 0; michael@0: offset = 0; michael@0: result.ptr = NULL; michael@0: michael@0: /* Skip the leading zeros */ michael@0: while(buffer[count] == DIGIT_0 || u_isspace(buffer[count])) { michael@0: count++; michael@0: offset++; michael@0: } michael@0: michael@0: /* iterate through buffer, stop when you hit the end */ michael@0: while(ufmt_isdigit(buffer[count], 16) && count < *len) { michael@0: /* increment the count consumed */ michael@0: ++count; michael@0: } michael@0: michael@0: /* detect overflow */ michael@0: if (count - offset > (int32_t)(sizeof(void*)*NIBBLE_PER_BYTE)) { michael@0: offset = count - (int32_t)(sizeof(void*)*NIBBLE_PER_BYTE); michael@0: } michael@0: michael@0: /* Initialize the direction of the input */ michael@0: #if U_IS_BIG_ENDIAN michael@0: incVal = -1; michael@0: resultIdx = (int32_t)(sizeof(void*) - 1); michael@0: #else michael@0: incVal = 1; michael@0: resultIdx = 0; michael@0: #endif michael@0: /* Write how much was consumed. */ michael@0: *len = count; michael@0: while(--count >= offset) { michael@0: /* Get the first nibble of the byte */ michael@0: uint8_t byte = (uint8_t)ufmt_digitvalue(buffer[count]); michael@0: michael@0: if (count > offset) { michael@0: /* Get the second nibble of the byte when available */ michael@0: byte = (uint8_t)(byte + (ufmt_digitvalue(buffer[--count]) << 4)); michael@0: } michael@0: /* Write the byte into the array */ michael@0: result.bytes[resultIdx] = byte; michael@0: resultIdx += incVal; michael@0: } michael@0: michael@0: return result.ptr; michael@0: } michael@0: michael@0: UChar* michael@0: ufmt_defaultCPToUnicode(const char *s, int32_t sSize, michael@0: UChar *target, int32_t tSize) michael@0: { michael@0: UChar *alias; michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: UConverter *defConverter = u_getDefaultConverter(&status); michael@0: michael@0: if(U_FAILURE(status) || defConverter == 0) michael@0: return 0; michael@0: michael@0: if(sSize <= 0) { michael@0: sSize = uprv_strlen(s) + 1; michael@0: } michael@0: michael@0: /* perform the conversion in one swoop */ michael@0: if(target != 0) { michael@0: michael@0: alias = target; michael@0: ucnv_toUnicode(defConverter, &alias, alias + tSize, &s, s + sSize - 1, michael@0: NULL, TRUE, &status); michael@0: michael@0: michael@0: /* add the null terminator */ michael@0: *alias = 0x0000; michael@0: } michael@0: michael@0: u_releaseDefaultConverter(defConverter); michael@0: michael@0: return target; michael@0: } michael@0: michael@0: