Length (1-4) of a well-formed UTF-8 sequence starting at p with `avail` bytes remaining, or 0 if the bytes are not well-formed UTF-8. Follows the Unicode 3.9 well-formed byte-sequence table: rejects overlong encodings, UTF-16 surrogates (U+D800–U+DFFF), and codepoints above U+10FFFF, as well as lone continuation bytes and truncated sequences. This is what tells a real non-ASCII filename apart from
| 96 | // lone continuation bytes and truncated sequences. This is what tells a real |
| 97 | // non-ASCII filename apart from binary garbage in a corrupt/hostile dentry. |
| 98 | int utf8_sequence_len(const unsigned char* p, std::size_t avail) { |
| 99 | const unsigned char c = p[0]; |
| 100 | if (c < 0x80) return 1; |
| 101 | auto cont = [](unsigned char b, unsigned char lo, unsigned char hi) { |
| 102 | return b >= lo && b <= hi; |
| 103 | }; |
| 104 | if (c >= 0xC2 && c <= 0xDF) |
| 105 | return (avail >= 2 && cont(p[1], 0x80, 0xBF)) ? 2 : 0; |
| 106 | if (c == 0xE0) |
| 107 | return (avail >= 3 && cont(p[1], 0xA0, 0xBF) && cont(p[2], 0x80, 0xBF)) ? 3 : 0; |
| 108 | if (c >= 0xE1 && c <= 0xEC) |
| 109 | return (avail >= 3 && cont(p[1], 0x80, 0xBF) && cont(p[2], 0x80, 0xBF)) ? 3 : 0; |
| 110 | if (c == 0xED) // exclude surrogates: second byte capped at 0x9F |
| 111 | return (avail >= 3 && cont(p[1], 0x80, 0x9F) && cont(p[2], 0x80, 0xBF)) ? 3 : 0; |
| 112 | if (c >= 0xEE && c <= 0xEF) |
| 113 | return (avail >= 3 && cont(p[1], 0x80, 0xBF) && cont(p[2], 0x80, 0xBF)) ? 3 : 0; |
| 114 | if (c == 0xF0) |
| 115 | return (avail >= 4 && cont(p[1], 0x90, 0xBF) && cont(p[2], 0x80, 0xBF) && |
| 116 | cont(p[3], 0x80, 0xBF)) ? 4 : 0; |
| 117 | if (c >= 0xF1 && c <= 0xF3) |
| 118 | return (avail >= 4 && cont(p[1], 0x80, 0xBF) && cont(p[2], 0x80, 0xBF) && |
| 119 | cont(p[3], 0x80, 0xBF)) ? 4 : 0; |
| 120 | if (c == 0xF4) // cap at U+10FFFF: second byte 0x80–0x8F |
| 121 | return (avail >= 4 && cont(p[1], 0x80, 0x8F) && cont(p[2], 0x80, 0xBF) && |
| 122 | cont(p[3], 0x80, 0xBF)) ? 4 : 0; |
| 123 | return 0; // 0x80–0xBF lone, 0xC0/0xC1 overlong, 0xF5–0xFF out of range |
| 124 | } |
| 125 | |
| 126 | PathTrust validate_path_component(std::string_view comp) { |
| 127 | if (comp.empty()) return {false, "empty path component"}; |
no outgoing calls
no test coverage detected