summaryrefslogtreecommitdiffstats
path: root/src/common/utf8.c
blob: be5d2b22e97a2bc563878f14c3aca123b782c045 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// SPDX-FileCopyrightText: 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
// SPDX-FileCopyrightText: 2014-2024 Rafael G. Martins <rafael@rafaelmartins.eng.br>
// SPDX-License-Identifier: MIT

// Based on Bjoern Hoehrmann's algorithm.
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "utils.h"

#define UTF8_ACCEPT 0
#define UTF8_REJECT 12


static const uint8_t utf8d[] = {
    // The first part of the table maps bytes to character classes that
    // to reduce the size of the transition table and create bitmasks.
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,  9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
     8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
    10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,

    // The second part is a transition table that maps a combination
    // of a state of the automaton and a character class to a state.
     0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
    12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
    12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
    12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
    12,36,12,12,12,12,12,12,12,12,12,12,
};


bool
bc_utf8_validate(const uint8_t *str, size_t len)
{
    uint32_t state = 0;

    for (size_t i = 0; i < len; i++)
        state = utf8d[256 + state + utf8d[str[i]]];

    return state == UTF8_ACCEPT;
}


bool
bc_utf8_validate_str(bc_string_t *str)
{
    return bc_utf8_validate((uint8_t*) str->str, str->len);
}


size_t
bc_utf8_skip_bom(const uint8_t *str, size_t len)
{
    if (len < 3)
        return 0;

    if (str[0] == 0xef && str[1] == 0xbb && str[2] == 0xbf)
        return 3;

    return 0;
}