aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/mds-kbdc/string.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/src/mds-kbdc/string.c b/src/mds-kbdc/string.c
index ca33b83..82797f3 100644
--- a/src/mds-kbdc/string.c
+++ b/src/mds-kbdc/string.c
@@ -82,3 +82,40 @@ char32_t* string_decode(const char* restrict string)
return rc[length] = -1, rc;
}
+
+/**
+ * Convert a -1-terminated UTF-32 string to a NUL-terminated Modified UTF-8 string.
+ *
+ * @param string The UTF-32 string.
+ * @return The string in UTF-8, `NULL` on error.
+ */
+char* string_encode(const char32_t* restrict string)
+{
+ size_t i, j, n = string_length(string);
+ char* restrict rc;
+
+ /* Allocated Modified UTF-8 string. */
+ if (xmalloc(rc, 6 * n + 1, char))
+ return NULL;
+
+ /* Convert to Modified UTF-8. */
+ for (i = j = 0; i < n; i++)
+ {
+#define _c(s) rc[j++] = (char)(((c >> (s)) & 0x3F) | 0x80)
+#define _t(s) t < (char32_t)(1L << s)
+ char32_t c = string[i];
+ if (c == 0) rc[j++] = 0xC0, rc[j++] = 0x80;
+ else if (_t( 7)) rc[j++] = (char)c;
+ else if (_t(11)) rc[j++] = (char)((c >> 6) | 0xC0), _c( 0);
+ else if (_t(16)) rc[j++] = (char)((c >> 12) | 0xE0), _c( 6), _c( 0);
+ else if (_t(21)) rc[j++] = (char)((c >> 18) | 0xF0), _c(12), _c( 6), _c( 0);
+ else if (_t(26)) rc[j++] = (char)((c >> 24) | 0xF8), _c(18), _c(12), _c( 6), _c(0);
+ else rc[j++] = (char)((c >> 30) | 0xFC), _c(24), _c(18), _c(12), _c(6), _c(0);
+#undef _t
+#undef _c
+ }
+
+ /* NUL-terminate and return. */
+ return rc[j] = '\0', rc;
+}
+