ds: string: replace utf-8 functions with b_wchar_utf8 interface
This commit is contained in:
204
ds/string.c
204
ds/string.c
@@ -59,174 +59,6 @@ static char *string_ptr(const struct b_string_p *str)
|
|||||||
return str->s_data.d_external;
|
return str->s_data.d_external;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t utf8_codepoint_size(b_wchar c)
|
|
||||||
{
|
|
||||||
if (!IS_VALID_UTF8_SCALAR(c)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c <= 0x7F) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c <= 0x7FF) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c <= 0xFFFF) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c <= 0x10FFFF) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t decode_utf8_trailer_byte(char c)
|
|
||||||
{
|
|
||||||
if (!(c & 0x80) || (c & 0x40)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return c & 0x3F;
|
|
||||||
}
|
|
||||||
|
|
||||||
static b_wchar utf8_codepoint_decode(const char *s)
|
|
||||||
{
|
|
||||||
b_wchar result = 0;
|
|
||||||
int len = 0;
|
|
||||||
|
|
||||||
if (!(s[0] & 0x80)) {
|
|
||||||
len = 1;
|
|
||||||
result = s[0] & 0x7F;
|
|
||||||
} else if (s[0] & 0xC0 && !(s[0] & 0x20)) {
|
|
||||||
len = 2;
|
|
||||||
result = s[0] & 0x1F;
|
|
||||||
result <<= 6;
|
|
||||||
} else if (s[0] & 0xE0 && !(s[0] & 0x10)) {
|
|
||||||
len = 3;
|
|
||||||
result = s[0] & 0x0F;
|
|
||||||
result <<= 12;
|
|
||||||
} else if (s[0] & 0xF0 && !(s[0] & 0x08)) {
|
|
||||||
len = 4;
|
|
||||||
result = s[0] & 0x07;
|
|
||||||
result <<= 18;
|
|
||||||
} else {
|
|
||||||
return B_WCHAR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i < len; i++) {
|
|
||||||
int32_t c = decode_utf8_trailer_byte(s[i]);
|
|
||||||
if (c == -1) {
|
|
||||||
return B_WCHAR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
c <<= 6 * (len - i - 1);
|
|
||||||
result |= c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IS_VALID_UTF8_SCALAR(result)) {
|
|
||||||
return B_WCHAR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t utf8_codepoint_encode(b_wchar c, char s[4])
|
|
||||||
{
|
|
||||||
size_t len = utf8_codepoint_size(c);
|
|
||||||
|
|
||||||
switch (len) {
|
|
||||||
case 1:
|
|
||||||
s[0] = c & 0x7F;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
s[0] = ((c >> 6) & 0x1F) | 0xC0;
|
|
||||||
s[1] = (c & 0x3F) | 0x80;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
s[0] = ((c >> 12) & 0x0F) | 0xE0;
|
|
||||||
s[1] = ((c >> 6) & 0x3F) | 0x80;
|
|
||||||
s[2] = (c & 0x3F) | 0x80;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
s[0] = ((c >> 18) & 0x07) | 0xF0;
|
|
||||||
s[1] = ((c >> 12) & 0x3F) | 0x80;
|
|
||||||
s[2] = ((c >> 6) & 0x3F) | 0x80;
|
|
||||||
s[3] = (c & 0x3F) | 0x80;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t codepoint_stride(const char *s)
|
|
||||||
{
|
|
||||||
char c = *s;
|
|
||||||
|
|
||||||
if (!(c & 0x80)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((c & 0xC0) && !(c & 0x20)) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((c & 0xE0) && !(c & 0x10)) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((c & 0xF0) && !(c & 0x08)) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t get_number_of_codepoints(const char *s, size_t len)
|
|
||||||
{
|
|
||||||
size_t nr_codepoints = 0;
|
|
||||||
const char *end = s + len;
|
|
||||||
|
|
||||||
while (*s && s < end) {
|
|
||||||
size_t stride = codepoint_stride(s);
|
|
||||||
if (stride == 0) {
|
|
||||||
/* invalid codepoint */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
nr_codepoints++;
|
|
||||||
s += stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*s != 0) {
|
|
||||||
/* string is not null-terminated */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nr_codepoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t get_utf8_encoded_size(const b_wchar *s, size_t nr_codepoints)
|
|
||||||
{
|
|
||||||
size_t len = 0;
|
|
||||||
for (size_t i = 0; i < nr_codepoints; i++) {
|
|
||||||
size_t l = utf8_codepoint_size(s[i]);
|
|
||||||
if (l == 0) {
|
|
||||||
/* invalid codepoint */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
len += l;
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum b_status convert_codepoint_range_to_byte_range(
|
static enum b_status convert_codepoint_range_to_byte_range(
|
||||||
const struct b_string_p *str, size_t cp_start, size_t cp_length,
|
const struct b_string_p *str, size_t cp_start, size_t cp_length,
|
||||||
size_t *out_byte_start, size_t *out_byte_length)
|
size_t *out_byte_start, size_t *out_byte_length)
|
||||||
@@ -241,7 +73,7 @@ static enum b_status convert_codepoint_range_to_byte_range(
|
|||||||
return B_ERR_OUT_OF_BOUNDS;
|
return B_ERR_OUT_OF_BOUNDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t stride = codepoint_stride(cp);
|
size_t stride = b_wchar_utf8_codepoint_stride(cp);
|
||||||
if (!stride) {
|
if (!stride) {
|
||||||
/* invalid codepoint */
|
/* invalid codepoint */
|
||||||
return B_ERR_BAD_STATE;
|
return B_ERR_BAD_STATE;
|
||||||
@@ -258,7 +90,7 @@ static enum b_status convert_codepoint_range_to_byte_range(
|
|||||||
return B_ERR_OUT_OF_BOUNDS;
|
return B_ERR_OUT_OF_BOUNDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t stride = codepoint_stride(cp);
|
size_t stride = b_wchar_utf8_codepoint_stride(cp);
|
||||||
if (!stride) {
|
if (!stride) {
|
||||||
/* invalid codepoint */
|
/* invalid codepoint */
|
||||||
return B_ERR_BAD_STATE;
|
return B_ERR_BAD_STATE;
|
||||||
@@ -524,7 +356,7 @@ static enum b_status replace_utf8(
|
|||||||
|
|
||||||
size_t new_data_nr_bytes = strlen(new_data);
|
size_t new_data_nr_bytes = strlen(new_data);
|
||||||
size_t new_data_nr_codepoints
|
size_t new_data_nr_codepoints
|
||||||
= get_number_of_codepoints(new_data, new_data_nr_bytes);
|
= b_wchar_utf8_codepoint_count(new_data, new_data_nr_bytes);
|
||||||
if (new_data_nr_codepoints == 0) {
|
if (new_data_nr_codepoints == 0) {
|
||||||
/* new_data is not a valid utf-8 string */
|
/* new_data is not a valid utf-8 string */
|
||||||
return B_ERR_INVALID_ARGUMENT;
|
return B_ERR_INVALID_ARGUMENT;
|
||||||
@@ -697,7 +529,7 @@ static enum b_status trim_utf8(struct b_string_p *str)
|
|||||||
size_t whitespace_end = 0;
|
size_t whitespace_end = 0;
|
||||||
size_t nr_whitespace_codepoints = 0;
|
size_t nr_whitespace_codepoints = 0;
|
||||||
for (size_t i = 0; i < str->s_len;) {
|
for (size_t i = 0; i < str->s_len;) {
|
||||||
b_wchar c = utf8_codepoint_decode(&s[i]);
|
b_wchar c = b_wchar_utf8_codepoint_decode(&s[i]);
|
||||||
|
|
||||||
if (!b_wchar_is_space(s[i])) {
|
if (!b_wchar_is_space(s[i])) {
|
||||||
whitespace_end = i;
|
whitespace_end = i;
|
||||||
@@ -717,8 +549,8 @@ static enum b_status trim_utf8(struct b_string_p *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (long i = str->s_len - 1; i >= 0;) {
|
for (long i = str->s_len - 1; i >= 0;) {
|
||||||
b_wchar c = utf8_codepoint_decode(p);
|
b_wchar c = b_wchar_utf8_codepoint_decode(p);
|
||||||
size_t c_size = utf8_codepoint_size(c);
|
size_t c_size = b_wchar_utf8_codepoint_size(c);
|
||||||
|
|
||||||
if (b_wchar_is_space(c)) {
|
if (b_wchar_is_space(c)) {
|
||||||
memset(p, 0, c_size);
|
memset(p, 0, c_size);
|
||||||
@@ -808,7 +640,7 @@ static enum b_status string_insert_cstr_utf8(
|
|||||||
dest_buf[new_total_bytes] = '\0';
|
dest_buf[new_total_bytes] = '\0';
|
||||||
|
|
||||||
dest->s_len += nr_bytes;
|
dest->s_len += nr_bytes;
|
||||||
dest->s_codepoints += get_number_of_codepoints(src, nr_bytes);
|
dest->s_codepoints += b_wchar_utf8_codepoint_count(src, nr_bytes);
|
||||||
|
|
||||||
return B_SUCCESS;
|
return B_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -820,7 +652,8 @@ static enum b_status string_insert_wstr_ansi(
|
|||||||
at = dest->s_len;
|
at = dest->s_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t utf8_encoded_size = get_utf8_encoded_size(src, nr_codepoints);
|
size_t utf8_encoded_size
|
||||||
|
= b_wchar_utf8_string_encoded_size(src, nr_codepoints);
|
||||||
if (utf8_encoded_size == 0) {
|
if (utf8_encoded_size == 0) {
|
||||||
return B_ERR_INVALID_ARGUMENT;
|
return B_ERR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
@@ -838,7 +671,7 @@ static enum b_status string_insert_wstr_ansi(
|
|||||||
char *ptr = dest_buf + at;
|
char *ptr = dest_buf + at;
|
||||||
for (size_t i = 0; i < nr_codepoints; i++) {
|
for (size_t i = 0; i < nr_codepoints; i++) {
|
||||||
char c[4];
|
char c[4];
|
||||||
size_t c_len = utf8_codepoint_encode(src[i], c);
|
size_t c_len = b_wchar_utf8_codepoint_encode(src[i], c);
|
||||||
if (c_len == 0) {
|
if (c_len == 0) {
|
||||||
/* the input string was already checked by
|
/* the input string was already checked by
|
||||||
* get_utf8_encoded_size, so this should never happen */
|
* get_utf8_encoded_size, so this should never happen */
|
||||||
@@ -865,7 +698,8 @@ static enum b_status string_insert_wstr_utf8(
|
|||||||
codepoint_offset = dest->s_codepoints;
|
codepoint_offset = dest->s_codepoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t utf8_encoded_size = get_utf8_encoded_size(src, nr_codepoints);
|
size_t utf8_encoded_size
|
||||||
|
= b_wchar_utf8_string_encoded_size(src, nr_codepoints);
|
||||||
if (utf8_encoded_size == 0) {
|
if (utf8_encoded_size == 0) {
|
||||||
return B_ERR_INVALID_ARGUMENT;
|
return B_ERR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
@@ -897,7 +731,7 @@ static enum b_status string_insert_wstr_utf8(
|
|||||||
char *ptr = dest_buf + move_offset;
|
char *ptr = dest_buf + move_offset;
|
||||||
for (size_t i = 0; i < nr_codepoints; i++) {
|
for (size_t i = 0; i < nr_codepoints; i++) {
|
||||||
char c[4];
|
char c[4];
|
||||||
size_t c_len = utf8_codepoint_encode(src[i], c);
|
size_t c_len = b_wchar_utf8_codepoint_encode(src[i], c);
|
||||||
if (c_len == 0) {
|
if (c_len == 0) {
|
||||||
/* the input string was already checked by
|
/* the input string was already checked by
|
||||||
* get_utf8_encoded_size, so this should never happen */
|
* get_utf8_encoded_size, so this should never happen */
|
||||||
@@ -1036,13 +870,13 @@ static enum b_status find_next_token(struct b_string_iterator *it)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
b_wchar c = utf8_codepoint_decode(s);
|
b_wchar c = b_wchar_utf8_codepoint_decode(s);
|
||||||
if (c == B_WCHAR_INVALID) {
|
if (c == B_WCHAR_INVALID) {
|
||||||
return B_ERR_BAD_STATE;
|
return B_ERR_BAD_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
b_string_append_wc(it->_tmp, c);
|
b_string_append_wc(it->_tmp, c);
|
||||||
offset += utf8_codepoint_size(c);
|
offset += b_wchar_utf8_codepoint_size(c);
|
||||||
|
|
||||||
if (offset > it->_s_p->s_len) {
|
if (offset > it->_s_p->s_len) {
|
||||||
break;
|
break;
|
||||||
@@ -1230,7 +1064,7 @@ b_string *b_string_create_from_cstr(const char *s)
|
|||||||
struct b_string_p *p = b_object_get_private(str, B_TYPE_STRING);
|
struct b_string_p *p = b_object_get_private(str, B_TYPE_STRING);
|
||||||
|
|
||||||
size_t s_len = strlen(s);
|
size_t s_len = strlen(s);
|
||||||
size_t s_codepoints = get_number_of_codepoints(s, s_len);
|
size_t s_codepoints = b_wchar_utf8_codepoint_count(s, s_len);
|
||||||
b_string_reserve(str, s_len);
|
b_string_reserve(str, s_len);
|
||||||
|
|
||||||
char *dest = string_ptr(p);
|
char *dest = string_ptr(p);
|
||||||
@@ -1577,7 +1411,7 @@ int b_string_iterator_begin(const b_string *string, b_string_iterator *it)
|
|||||||
const char *s = string_ptr(p);
|
const char *s = string_ptr(p);
|
||||||
it->_m = ITERATOR_MODE_CHARS;
|
it->_m = ITERATOR_MODE_CHARS;
|
||||||
it->_s_p = p;
|
it->_s_p = p;
|
||||||
it->char_value = utf8_codepoint_decode(s);
|
it->char_value = b_wchar_utf8_codepoint_decode(s);
|
||||||
|
|
||||||
if (it->char_value == B_WCHAR_INVALID) {
|
if (it->char_value == B_WCHAR_INVALID) {
|
||||||
it->status = B_ERR_BAD_FORMAT;
|
it->status = B_ERR_BAD_FORMAT;
|
||||||
@@ -1593,7 +1427,7 @@ static bool chars_iterator_next(b_string_iterator *it)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t stride = utf8_codepoint_size(it->char_value);
|
size_t stride = b_wchar_utf8_codepoint_size(it->char_value);
|
||||||
if (stride == 0) {
|
if (stride == 0) {
|
||||||
iterator_cleanup(it);
|
iterator_cleanup(it);
|
||||||
return false;
|
return false;
|
||||||
@@ -1613,7 +1447,7 @@ static bool chars_iterator_next(b_string_iterator *it)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *p = string_ptr(it->_s_p) + it->byte_index;
|
char *p = string_ptr(it->_s_p) + it->byte_index;
|
||||||
it->char_value = utf8_codepoint_decode(p);
|
it->char_value = b_wchar_utf8_codepoint_decode(p);
|
||||||
if (it->char_value == B_WCHAR_INVALID) {
|
if (it->char_value == B_WCHAR_INVALID) {
|
||||||
iterator_cleanup(it);
|
iterator_cleanup(it);
|
||||||
it->_s_p = NULL;
|
it->_s_p = NULL;
|
||||||
|
|||||||
Reference in New Issue
Block a user