Coverage Report

Created: 2026-09-01 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/utf8.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
#include <string.h>
15
16
#include <isc/utf8.h>
17
#include <isc/util.h>
18
19
/*
20
 * UTF-8 is defined in "The Unicode Standard -- Version 4.0"
21
 * Also see RFC 3629.
22
 *
23
 * Char. number range  |        UTF-8 octet sequence
24
 *    (hexadecimal)    |              (binary)
25
 *  --------------------+---------------------------------------------
26
 * 0000 0000-0000 007F | 0xxxxxxx
27
 * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
28
 * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
29
 * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
30
 */
31
bool
32
21.7k
isc_utf8_valid(const unsigned char *buf, size_t len) {
33
21.7k
  REQUIRE(buf != NULL);
34
35
645k
  for (size_t i = 0; i < len; i++) {
36
    /*
37
     * ASCII character range (first row).
38
     */
39
623k
    if (buf[i] <= 0x7f) {
40
615k
      continue;
41
615k
    }
42
43
    /*
44
     * 0x80 -> 1000 0000
45
     * 0xC0 -> 1100 0000
46
     * 0xE0 -> 1110 0000
47
     *
48
     * Is unicode character is encoded using 2 bytes (second row).
49
     */
50
7.81k
    if ((i + 1) < len && (buf[i] & 0xe0) == 0xc0 &&
51
2.73k
        (buf[i + 1] & 0xc0) == 0x80)
52
2.69k
    {
53
2.69k
      unsigned int w;
54
2.69k
      w = (buf[i] & 0x1f) << 6;
55
2.69k
      w |= (buf[++i] & 0x3f);
56
2.69k
      if (w < 0x80) {
57
6
        return false;
58
6
      }
59
2.69k
      continue;
60
2.69k
    }
61
62
    /*
63
     * 0x80 -> 1000 0000
64
     * 0xC0 -> 1100 0000
65
     * 0xE0 -> 1110 0000
66
     * 0xF0 -> 1111 0000
67
     *
68
     * Is unicode character is encoded within 3 bytes (third row).
69
     */
70
5.11k
    if ((i + 2) < len && (buf[i] & 0xf0) == 0xe0 &&
71
3.03k
        (buf[i + 1] & 0xc0) == 0x80 && (buf[i + 2] & 0xc0) == 0x80)
72
2.99k
    {
73
2.99k
      unsigned int w;
74
2.99k
      w = (buf[i] & 0x0f) << 12;
75
2.99k
      w |= (buf[++i] & 0x3f) << 6;
76
2.99k
      w |= (buf[++i] & 0x3f);
77
2.99k
      if (w < 0x0800) {
78
20
        return false;
79
20
      }
80
81
      /*
82
       * Unicode range 0xD800..0xDFFF is reserved (UTF16
83
       * surrogates)
84
       */
85
2.97k
      if (w >= 0xD800 && w <= 0xDFFF) {
86
5
        return false;
87
5
      }
88
2.97k
      continue;
89
2.97k
    }
90
91
    /*
92
     * 0x80 -> 1000 0000
93
     * 0xC0 -> 1100 0000
94
     * 0xE0 -> 1110 0000
95
     * 0xF0 -> 1111 0000
96
     * 0xF8 -> 1111 1000
97
     *
98
     * Is unicode character is encoded within 4 bytes (fourth row).
99
     */
100
2.11k
    if ((i + 3) < len && (buf[i] & 0xf8) == 0xf0 &&
101
1.93k
        (buf[i + 1] & 0xc0) == 0x80 &&
102
1.92k
        (buf[i + 2] & 0xc0) == 0x80 && (buf[i + 3] & 0xc0) == 0x80)
103
1.90k
    {
104
1.90k
      unsigned int w;
105
1.90k
      w = (buf[i] & 0x07) << 18;
106
1.90k
      w |= (buf[++i] & 0x3f) << 12;
107
1.90k
      w |= (buf[++i] & 0x3f) << 6;
108
1.90k
      w |= (buf[++i] & 0x3f);
109
1.90k
      if (w < 0x10000 || w > 0x10FFFF) {
110
24
        return false;
111
24
      }
112
1.88k
      continue;
113
1.90k
    }
114
207
    return false;
115
2.11k
  }
116
21.4k
  return true;
117
21.7k
}
118
119
bool
120
12.9k
isc_utf8_bom(const unsigned char *buf, size_t len) {
121
12.9k
  REQUIRE(buf != NULL);
122
123
12.9k
  if (len >= 3U && !memcmp(buf, "\xef\xbb\xbf", 3)) {
124
1
    return true;
125
1
  }
126
12.9k
  return false;
127
12.9k
}