Skip to content
API Documentation
BastionGuard™
text_utils Namespace Reference

Functions

std::string utf16le_to_utf8 (const unsigned char *data, std::size_t byte_count)
std::string sanitize_component (const std::string &in)

Function Documentation

◆ sanitize_component()

std::string text_utils::sanitize_component ( const std::string & in)
inline

Definition at line 79 of file text_utils.hpp.

79 {
80 // Trim trailing dots and spaces from the INPUT first (Windows rule).
81 std::size_t end = in.size();
82 while (end > 0 && (in[end - 1] == '.' || in[end - 1] == ' ' || in[end - 1] == '\t')) {
83 --end;
84 }
85
86 std::string out;
87 out.reserve(end);
88 for (std::size_t i = 0; i < end; ) {
89 const unsigned char c = static_cast<unsigned char>(in[i]);
90
91 // ASCII branch
92 if (c < 0x80) {
93 // Forbidden filename characters across Windows + POSIX
94 const bool forbidden =
95 c < 0x20 || c == 0x7F ||
96 c == '/' || c == '\\' || c == ':' || c == '*' ||
97 c == '?' || c == '"' || c == '<' || c == '>' || c == '|';
98 if (forbidden) {
99 out.push_back('_');
100 } else if (c == ' ' || c == '\t') {
101 out.push_back('_');
102 } else {
103 out.push_back(static_cast<char>(c));
104 }
105 ++i;
106 continue;
107 }
108
109 // UTF-8 multibyte: count expected length
110 std::size_t expected = 0;
111 if ((c & 0xE0) == 0xC0) expected = 2;
112 else if ((c & 0xF0) == 0xE0) expected = 3;
113 else if ((c & 0xF8) == 0xF0) expected = 4;
114 else {
115 // invalid lead byte
116 out.push_back('_');
117 ++i;
118 continue;
119 }
120 if (i + expected > end) {
121 out.push_back('_');
122 ++i;
123 continue;
124 }
125 // Validate continuation bytes
126 bool valid = true;
127 for (std::size_t k = 1; k < expected; ++k) {
128 if ((static_cast<unsigned char>(in[i + k]) & 0xC0) != 0x80) {
129 valid = false;
130 break;
131 }
132 }
133 if (!valid) {
134 out.push_back('_');
135 ++i;
136 continue;
137 }
138 // Append the whole UTF-8 sequence as-is
139 for (std::size_t k = 0; k < expected; ++k) {
140 out.push_back(in[i + k]);
141 }
142 i += expected;
143 }
144
145 if (out.empty()) out = "unnamed";
146 return out;
147}

References sanitize_component().

Referenced by XfsRecovery::recover(), anonymous_namespace{btrfs_recovery.cpp}::sanitize(), anonymous_namespace{ntfs_recovery.cpp}::sanitize_component(), sanitize_component(), anonymous_namespace{ext4_recovery.cpp}::sanitize_path_component(), and anonymous_namespace{filesystem_recovery.cpp}::sanitize_path_component().

◆ utf16le_to_utf8()

std::string text_utils::utf16le_to_utf8 ( const unsigned char * data,
std::size_t byte_count )
inline

Definition at line 21 of file text_utils.hpp.

21 {
22 std::string out;
23 out.reserve(byte_count);
24 auto read_unit = [&](std::size_t i) -> uint16_t {
25 return static_cast<uint16_t>(data[i]) |
26 (static_cast<uint16_t>(data[i + 1]) << 8);
27 };
28 auto append_utf8 = [&](uint32_t cp) {
29 if (cp < 0x80) {
30 out.push_back(static_cast<char>(cp));
31 } else if (cp < 0x800) {
32 out.push_back(static_cast<char>(0xC0 | (cp >> 6)));
33 out.push_back(static_cast<char>(0x80 | (cp & 0x3F)));
34 } else if (cp < 0x10000) {
35 out.push_back(static_cast<char>(0xE0 | (cp >> 12)));
36 out.push_back(static_cast<char>(0x80 | ((cp >> 6) & 0x3F)));
37 out.push_back(static_cast<char>(0x80 | (cp & 0x3F)));
38 } else if (cp <= 0x10FFFF) {
39 out.push_back(static_cast<char>(0xF0 | (cp >> 18)));
40 out.push_back(static_cast<char>(0x80 | ((cp >> 12) & 0x3F)));
41 out.push_back(static_cast<char>(0x80 | ((cp >> 6) & 0x3F)));
42 out.push_back(static_cast<char>(0x80 | (cp & 0x3F)));
43 }
44 };
45 std::size_t i = 0;
46 while (i + 1 < byte_count) {
47 const uint16_t unit = read_unit(i);
48 if (unit == 0) break;
49 // High surrogate: combine with next low surrogate
50 if (unit >= 0xD800 && unit <= 0xDBFF && i + 3 < byte_count) {
51 const uint16_t low = read_unit(i + 2);
52 if (low >= 0xDC00 && low <= 0xDFFF) {
53 const uint32_t cp = 0x10000 +
54 ((static_cast<uint32_t>(unit - 0xD800)) << 10) +
55 static_cast<uint32_t>(low - 0xDC00);
56 append_utf8(cp);
57 i += 4;
58 continue;
59 }
60 }
61 // Lone low surrogate or normal BMP code point
62 if (unit >= 0xDC00 && unit <= 0xDFFF) {
63 append_utf8(0xFFFD); // replacement char for invalid surrogate
64 } else {
65 append_utf8(unit);
66 }
67 i += 2;
68 }
69 return out;
70}
void append_utf8(std::string &out, uint32_t cp)

References utf16le_to_utf8().

Referenced by anonymous_namespace{filesystem_recovery.cpp}::Fat32Recovery::decode_lfn_part(), anonymous_namespace{filesystem_recovery.cpp}::ExfatRecovery::decode_utf16_name(), anonymous_namespace{ntfs_recovery.cpp}::decode_utf16le_ascii(), and utf16le_to_utf8().