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}