Coverage Report

Created: 2026-07-30 06:30

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
0
isc_utf8_valid(const unsigned char *buf, size_t len) {
33
0
  REQUIRE(buf != NULL);
34
35
0
  for (size_t i = 0; i < len; i++) {
36
    /*
37
     * ASCII character range (first row).
38
     */
39
0
    if (buf[i] <= 0x7f) {
40
0
      continue;
41
0
    }
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
0
    if ((i + 1) < len && (buf[i] & 0xe0) == 0xc0 &&
51
0
        (buf[i + 1] & 0xc0) == 0x80)
52
0
    {
53
0
      unsigned int w;
54
0
      w = (buf[i] & 0x1f) << 6;
55
0
      w |= (buf[++i] & 0x3f);
56
0
      if (w < 0x80) {
57
0
        return false;
58
0
      }
59
0
      continue;
60
0
    }
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
0
    if ((i + 2) < len && (buf[i] & 0xf0) == 0xe0 &&
71
0
        (buf[i + 1] & 0xc0) == 0x80 && (buf[i + 2] & 0xc0) == 0x80)
72
0
    {
73
0
      unsigned int w;
74
0
      w = (buf[i] & 0x0f) << 12;
75
0
      w |= (buf[++i] & 0x3f) << 6;
76
0
      w |= (buf[++i] & 0x3f);
77
0
      if (w < 0x0800) {
78
0
        return false;
79
0
      }
80
81
      /*
82
       * Unicode range 0xD800..0xDFFF is reserved (UTF16
83
       * surrogates)
84
       */
85
0
      if (w >= 0xD800 && w <= 0xDFFF) {
86
0
        return false;
87
0
      }
88
0
      continue;
89
0
    }
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
0
    if ((i + 3) < len && (buf[i] & 0xf8) == 0xf0 &&
101
0
        (buf[i + 1] & 0xc0) == 0x80 &&
102
0
        (buf[i + 2] & 0xc0) == 0x80 && (buf[i + 3] & 0xc0) == 0x80)
103
0
    {
104
0
      unsigned int w;
105
0
      w = (buf[i] & 0x07) << 18;
106
0
      w |= (buf[++i] & 0x3f) << 12;
107
0
      w |= (buf[++i] & 0x3f) << 6;
108
0
      w |= (buf[++i] & 0x3f);
109
0
      if (w < 0x10000 || w > 0x10FFFF) {
110
0
        return false;
111
0
      }
112
0
      continue;
113
0
    }
114
0
    return false;
115
0
  }
116
0
  return true;
117
0
}
118
119
bool
120
0
isc_utf8_bom(const unsigned char *buf, size_t len) {
121
0
  REQUIRE(buf != NULL);
122
123
0
  if (len >= 3U && !memcmp(buf, "\xef\xbb\xbf", 3)) {
124
0
    return true;
125
0
  }
126
0
  return false;
127
0
}