main
44ceea7 ยท 1 month ago 7 commits
 1#include <stdint.h>
 2#include <stddef.h>
 3#include <string.h>
 4#include "unicode.h"
 5
 6int utf8_last_size(const char *str) {
 7	int len = 0;
 8	char *pos = strchr(str, '\0');
 9	while (pos > str) {
10		--pos; ++len;
11		if ((*pos & 0xc0) != 0x80) {
12			return len;
13		}
14	}
15	return 0;
16}
17
18size_t utf8_chsize(uint32_t ch) {
19	if (ch < 0x80) {
20		return 1;
21	} else if (ch < 0x800) {
22		return 2;
23	} else if (ch < 0x10000) {
24		return 3;
25	}
26	return 4;
27}
28
29size_t utf8_encode(char *str, uint32_t ch) {
30	size_t len = 0;
31	uint8_t first;
32
33	if (ch < 0x80) {
34		first = 0;
35		len = 1;
36	} else if (ch < 0x800) {
37		first = 0xc0;
38		len = 2;
39	} else if (ch < 0x10000) {
40		first = 0xe0;
41		len = 3;
42	} else {
43		first = 0xf0;
44		len = 4;
45	}
46
47	for (size_t i = len - 1; i > 0; --i) {
48		str[i] = (ch & 0x3f) | 0x80;
49		ch >>= 6;
50	}
51
52	str[0] = ch | first;
53	return len;
54}
55
56
57static const struct {
58	uint8_t mask;
59	uint8_t result;
60	int octets;
61} sizes[] = {
62	{ 0x80, 0x00, 1 },
63	{ 0xE0, 0xC0, 2 },
64	{ 0xF0, 0xE0, 3 },
65	{ 0xF8, 0xF0, 4 },
66	{ 0xFC, 0xF8, 5 },
67	{ 0xFE, 0xF8, 6 },
68	{ 0x80, 0x80, -1 },
69};
70
71int utf8_size(const char *s) {
72	uint8_t c = (uint8_t)*s;
73	for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i) {
74		if ((c & sizes[i].mask) == sizes[i].result) {
75			return sizes[i].octets;
76		}
77	}
78	return -1;
79}