// Public NTLite string view ABI declarations shared between kernel, drivers, and user mode. #pragma once // sys_string.h - shared native string-view ABI. // A SYS_STRING_VIEW is a borrowed byte span. Length counts bytes, never Unicode // scalar values or characters. The view is not NUL-terminated and owns no storage. // Native names/text must contain strict UTF-8 (no normalization or case folding); // generic byte payloads may use the same representation without becoming text. #include #include #include #include #ifndef SYS_STRING_VIEW_DEFINED #define SYS_STRING_VIEW_DEFINED 1 typedef struct SYS_STRING_VIEW { const char* Data; size_t Length; } SYS_STRING_VIEW; #endif #define SYS_SV_LITERAL(s) ((SYS_STRING_VIEW){ (s), sizeof(s) - 1 }) #define SYS_SV_NULL ((SYS_STRING_VIEW){ (const char*)0, 0 }) static inline SYS_STRING_VIEW SysSvFromParts(const char* data, size_t length) { SYS_STRING_VIEW v; v.Data = data; v.Length = length; return v; } static inline SYS_STRING_VIEW SysSvFromCstr(const char* s) { SYS_STRING_VIEW v; v.Data = s; v.Length = s ? strlen(s) : 0; return v; } static inline bool SysSvIsEmpty(SYS_STRING_VIEW s) { return s.Length == 0; } static inline bool SysSvIsValid(SYS_STRING_VIEW s) { return s.Data != (const char*)0 || s.Length == 0; } // Validates well-formed UTF-8 bytes (RFC 3629). No normalization is performed. // Rejects overlong encodings, surrogates, truncated sequences and > U+10FFFF. static inline bool SysSvIsUtf8(SYS_STRING_VIEW view) { if (!SysSvIsValid(view)) return false; const uint8_t* data = (const uint8_t*)view.Data; size_t i = 0; while (i < view.Length) { uint8_t lead = data[i++]; if (lead <= 0x7Fu) continue; uint32_t scalar; size_t continuation; if (lead >= 0xC2u && lead <= 0xDFu) { scalar = lead & 0x1Fu; continuation = 1; } else if (lead >= 0xE0u && lead <= 0xEFu) { scalar = lead & 0x0Fu; continuation = 2; } else if (lead >= 0xF0u && lead <= 0xF4u) { scalar = lead & 0x07u; continuation = 3; } else { return false; } if (continuation > view.Length - i) return false; for (size_t j = 0; j < continuation; ++j) { uint8_t byte = data[i++]; if ((byte & 0xC0u) != 0x80u) return false; scalar = (scalar << 6) | (uint32_t)(byte & 0x3Fu); } if ((continuation == 1 && scalar < 0x80u) || (continuation == 2 && scalar < 0x800u) || (continuation == 3 && scalar < 0x10000u) || (scalar >= 0xD800u && scalar <= 0xDFFFu) || scalar > 0x10FFFFu) return false; } return true; } // Names and other retained native text forbid embedded NUL as well as bad UTF-8. // Empty views, including the canonical null view, are valid text. static inline bool SysSvIsUtf8Text(SYS_STRING_VIEW view) { if (!SysSvIsUtf8(view)) return false; for (size_t i = 0; i < view.Length; ++i) if (view.Data[i] == '\0') return false; return true; } // Copies external filename bytes into display-only UTF-8, replacing each invalid // byte (including embedded NUL) with U+FFFD. Never splits a valid scalar or a // replacement at the output capacity; always NUL-terminates when capacity > 0. // This is a lossy display projection, not a native namespace identity mapping. static inline size_t SysSvCopyUtf8WithReplacement(SYS_STRING_VIEW source, char* destination, size_t capacity) { if (!destination || capacity == 0) return 0; size_t read = 0; size_t written = 0; if (!SysSvIsValid(source)) { destination[0] = '\0'; return 0; } while (read < source.Length) { uint8_t first = (uint8_t)source.Data[read]; size_t sequenceLength = 0; if (first >= 1u && first <= 0x7Fu) { sequenceLength = 1; } else if (first >= 0xC2u && first <= 0xDFu) { sequenceLength = 2; } else if (first >= 0xE0u && first <= 0xEFu) { sequenceLength = 3; } else if (first >= 0xF0u && first <= 0xF4u) { sequenceLength = 4; } bool valid = sequenceLength && sequenceLength <= source.Length - read && SysSvIsUtf8(SysSvFromParts(source.Data + read, sequenceLength)); size_t appendLength = valid ? sequenceLength : 3u; if (appendLength > capacity - written - 1u) break; if (valid) { memcpy(destination + written, source.Data + read, sequenceLength); read += sequenceLength; } else { destination[written] = (char)0xEF; destination[written + 1u] = (char)0xBF; destination[written + 2u] = (char)0xBD; ++read; } written += appendLength; } destination[written] = '\0'; return written; } static inline bool SysSvEqual(SYS_STRING_VIEW a, SYS_STRING_VIEW b) { if (a.Length != b.Length) return false; if (a.Length == 0) return true; if (!a.Data || !b.Data) return false; return memcmp(a.Data, b.Data, a.Length) == 0; } static inline char SysAsciiLower(char c) { return (c >= 'A' && c <= 'Z') ? (char)(c + ('a' - 'A')) : c; } static inline bool SysSvEqualAsciiI(SYS_STRING_VIEW a, SYS_STRING_VIEW b) { if (a.Length != b.Length) return false; if (a.Length == 0) return true; if (!a.Data || !b.Data) return false; for (size_t i = 0; i < a.Length; i++) { if (SysAsciiLower(a.Data[i]) != SysAsciiLower(b.Data[i])) return false; } return true; } static inline bool SysSvEqualLit(SYS_STRING_VIEW a, const char* lit) { return SysSvEqual(a, SysSvFromCstr(lit)); } static inline bool SysSvEqualLitAsciiI(SYS_STRING_VIEW a, const char* lit) { return SysSvEqualAsciiI(a, SysSvFromCstr(lit)); } static inline bool SysSvContainsByte(SYS_STRING_VIEW s, char ch) { if (!s.Data && s.Length) return false; for (size_t i = 0; i < s.Length; i++) { if (s.Data[i] == ch) return true; } return false; } static inline SYS_STRING_VIEW SysSvSlice(SYS_STRING_VIEW s, size_t off, size_t len) { if (off > s.Length) off = s.Length; if (len > s.Length - off) len = s.Length - off; return SysSvFromParts(s.Data ? s.Data + off : (const char*)0, len); } static inline SYS_STRING_VIEW SysSvTrimAscii(SYS_STRING_VIEW s) { if (!SysSvIsValid(s)) return SYS_SV_NULL; size_t begin = 0; size_t end = s.Length; while (begin < end) { char c = s.Data[begin]; if (c != ' ' && c != '\t' && c != '\r' && c != '\n') break; begin++; } while (end > begin) { char c = s.Data[end - 1]; if (c != ' ' && c != '\t' && c != '\r' && c != '\n') break; end--; } return SysSvSlice(s, begin, end - begin); } static inline bool SysSvCopyZ(char* dst, size_t dstSize, SYS_STRING_VIEW src) { if (!dst || dstSize == 0) return false; if (src.Length && !src.Data) return false; if (src.Length + 1 > dstSize) { dst[0] = '\0'; return false; } if (src.Length) memcpy(dst, src.Data, src.Length); dst[src.Length] = '\0'; return true; }