226 lines
7.8 KiB
C
226 lines
7.8 KiB
C
// 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 <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#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 })
|
|
|
|
// Implements the sv From Parts operation.
|
|
static inline SYS_STRING_VIEW SysSvFromParts(const char* data, size_t length) {
|
|
SYS_STRING_VIEW v;
|
|
v.Data = data;
|
|
v.Length = length;
|
|
return v;
|
|
}
|
|
|
|
// Implements the sv From Cstr operation.
|
|
static inline SYS_STRING_VIEW SysSvFromCstr(const char* s) {
|
|
SYS_STRING_VIEW v;
|
|
v.Data = s;
|
|
v.Length = s ? strlen(s) : 0;
|
|
return v;
|
|
}
|
|
|
|
// Implements the sv Is Empty operation.
|
|
static inline bool SysSvIsEmpty(SYS_STRING_VIEW s) {
|
|
return s.Length == 0;
|
|
}
|
|
|
|
// Implements the sv Is Valid operation.
|
|
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;
|
|
}
|
|
|
|
// Implements the sv Equal operation.
|
|
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;
|
|
}
|
|
|
|
// Implements the ascii Lower operation.
|
|
static inline char SysAsciiLower(char c) {
|
|
return (c >= 'A' && c <= 'Z') ? (char)(c + ('a' - 'A')) : c;
|
|
}
|
|
|
|
// Implements the sv Equal Ascii I operation.
|
|
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;
|
|
}
|
|
|
|
// Implements the sv Equal Lit operation.
|
|
static inline bool SysSvEqualLit(SYS_STRING_VIEW a, const char* lit) {
|
|
return SysSvEqual(a, SysSvFromCstr(lit));
|
|
}
|
|
|
|
// Implements the sv Equal Lit Ascii I operation.
|
|
static inline bool SysSvEqualLitAsciiI(SYS_STRING_VIEW a, const char* lit) {
|
|
return SysSvEqualAsciiI(a, SysSvFromCstr(lit));
|
|
}
|
|
|
|
// Implements the sv Contains Byte operation.
|
|
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;
|
|
}
|
|
|
|
// Implements the sv Slice operation.
|
|
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);
|
|
}
|
|
|
|
// Implements the sv Trim Ascii operation.
|
|
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);
|
|
}
|
|
|
|
// Implements the sv Copy Z operation.
|
|
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;
|
|
}
|