17typedef enum : uint8_t {
47 return (
char)(((c >=
'A') && (c <=
'Z')) ? (c + (
'a' -
'A')) : c);
66 return ((c >=
'A') && (c <=
'Z')) || ((c >=
'a') && (c <=
'z')) || ((c >=
'0') && (c <=
'9')) ||
67 (c ==
'.') || (c ==
'-') || (c ==
'_');
86 return (name[0] ==
'\0') || (
strcmp(name,
".") == 0) || (
strcmp(name,
"..") == 0);
105 while ((name[i] !=
'\0') && (name[i] !=
'.') && ((i + 1U) < cap)) {
168 if (raw !=
nullptr) {
170 while ((raw[i] !=
'\0') && ((n + 1U) < cap)) {
180 if (raw[i] !=
'\0') {
205 if ((keep + 2U) > cap) {
210 out[keep + 1] =
'\0';
215 if ((out ==
nullptr) || (cap < 2U)) {
233 if ((parent ==
nullptr) || (candidate ==
nullptr)) {
236 size_t plen =
strlen(parent);
237 while ((plen > 0U) && (parent[plen - 1U] ==
'/')) {
243 if (
strncmp(candidate, parent, plen) != 0) {
246 const char sep = candidate[plen];
247 return (sep ==
'/') || (sep ==
'\0');
266 return strchr(seg,
'/') !=
nullptr;
269bool mdl_path_join(
const char* parent,
const char* seg,
char* out,
size_t cap)
271 if ((out ==
nullptr) || (cap == 0U)) {
275 if ((parent ==
nullptr) || (seg ==
nullptr)) {
281 const size_t plen =
strlen(parent);
282 const size_t slen =
strlen(seg);
283 const size_t need = plen + 1U + slen + 1U;
287 memcpy(out, parent, plen);
289 memcpy(out + plen + 1U, seg, slen);
290 out[plen + 1U + slen] =
'\0';
315 if ((out ==
nullptr) || (cap == 0U)) {
319 if (src ==
nullptr) {
323 for (
size_t i = 0U; src[i] !=
'\0'; ++i) {
325 const size_t need = (ent !=
nullptr) ?
strlen(ent) : 1U;
326 if ((n + need + 1U) > cap) {
330 if (ent !=
nullptr) {
331 memcpy(out + n, ent, need);
static bool internal_is_dot_segment(const char *name)
True if name is empty, ".", or ".." (no useful segment).
bool mdl_xml_escape(const char *src, char *out, size_t cap)
XML-escape src into out, failing rather than truncating.
static bool internal_is_allowed_char(char c)
True if c may appear verbatim in a sanitised segment.
static const char *const s_reserved_exact[]
Exactly-reserved Windows device base names (case-folded).
bool mdl_path_join(const char *parent, const char *seg, char *out, size_t cap)
Join one safe child segment under a parent directory path.
static const char *const s_fallback_name
Fallback name substituted when a segment sanitises to nothing.
bool mdl_path_contained(const char *parent, const char *candidate)
True when candidate is lexically contained under parent.
static bool internal_has_separator(const char *seg)
True if seg embeds a path separator (would span directories).
static bool internal_is_reserved_base(const char *name)
True if name's base is a Windows reserved device name.
static void internal_prepend_underscore(char *out, size_t cap, size_t len)
Prepend _ to out in place, staying within cap.
mdl_sanitize_size_t
Small fixed sizes used while sanitising a name.
@ k_reserved_digit_at
Index of the digit in COMx / LPTx.
@ k_reserved_base_max
Buffer for a Windows reserved-name base.
@ k_reserved_len
Length of a COMx / LPTx reserved name.
static bool internal_copy_sanitised(const char *raw, char *out, size_t cap, size_t *out_len)
Copy raw into out replacing unsafe bytes; report bad/truncated.
static void internal_base_of(const char *name, char *base, size_t cap)
Case-folded base name (up to the first ".") of name into base.
static char internal_lower_ascii(char c)
ASCII lower-case of one character (locale-independent).
bool mdl_sanitize_segment(const char *raw, char *out, size_t cap)
Rewrite an untrusted path segment into a safe single filename.
static const char *const s_reserved_numbered[]
Reserved Windows device prefixes taking a 1-9 suffix.
static const char * internal_xml_entity(char c)
XML entity for a metacharacter, or NULL when c needs no escape.
Neutralise untrusted names before they reach a filesystem or XML sink.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
int strncmp(const char *s1, const char *s2, size_t n)
Compare two strings up to a specified length.
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
void * memmove(void *dst, const void *src, size_t n)
Copy memory area between potentially overlapping regions.
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
char * strchr(const char *s, int c)
Locate first occurrence of character in string.