aboutsummaryrefslogtreecommitdiffstats
path: root/libcmap_get_codepoint_data.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcmap_get_codepoint_data.c')
-rw-r--r--libcmap_get_codepoint_data.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/libcmap_get_codepoint_data.c b/libcmap_get_codepoint_data.c
new file mode 100644
index 0000000..553636d
--- /dev/null
+++ b/libcmap_get_codepoint_data.c
@@ -0,0 +1,123 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+static int
+construct_codepoint_label(const char *metalabel, uint32_t codepoint, void *buffer, size_t *bufsizep)
+{
+ /* See Unicode Core Spec 4.8.2 Code Point Labels */
+
+ size_t req = sizeof("-NNNN") + strlen(metalabel) - 2u * (size_t)(*metalabel == '<');
+ char *p = buffer;
+
+ if (codepoint >> 16) req += 1u;
+ if (codepoint >> 20) req += 1u;
+
+ if (*bufsizep < req) {
+ *bufsizep = req;
+ errno = ERANGE;
+ return -1;
+ }
+
+ p = stpcpy(buffer, &metalabel[*metalabel == '<']);
+ p -= *metalabel == '<';
+ *p++ = '-';
+ if (codepoint >> 20) *p++ = "0123456789ABCDEF"[(codepoint >> 20) & 15u];
+ if (codepoint >> 16) *p++ = "0123456789ABCDEF"[(codepoint >> 16) & 15u];
+ *p++ = "0123456789ABCDEF"[(codepoint >> 12) & 15u];
+ *p++ = "0123456789ABCDEF"[(codepoint >> 8) & 15u];
+ *p++ = "0123456789ABCDEF"[(codepoint >> 4) & 15u];
+ *p++ = "0123456789ABCDEF"[(codepoint >> 0) & 15u];
+ *p = '\0';
+
+ return 0;
+}
+
+
+int
+libcmap_get_codepoint_data(uint32_t codepoint, struct libcmap_codepoint_data *data_out, void *buffer, size_t *bufsizep)
+{
+ const struct libcmap_codepoint_data *data;
+ size_t i, namelen;
+ const char *metalabel;
+
+ memset(data_out, 0, sizeof(*data_out));
+ data_out->name = NULL;
+ data_out->unicode_1_name = NULL;
+ data_out->numeric_value = NULL;
+ data_out->decomposition_mapping = NULL;
+
+ if (codepoint > LIBCMAP_ULTIMATE_CODEPOINT)
+ return 0;
+
+ if ((0xFDD0u <= codepoint && codepoint <= 0xFDEFu) || (codepoint & 0xFFFEu) == 0xFFFEu) {
+ if (data_out) {
+ if (construct_codepoint_label("noncharacter", codepoint, buffer, bufsizep))
+ return -1;
+ data_out->name = buffer;
+ data_out->general_category = LIBCMAP_GENERAL_CATEGORY_OTHER_NOT_ASSIGNED;
+ data_out->noncharacter = 1u;
+ }
+ return 1;
+ }
+
+ for (i = 0u; i < libcmap_no_data_range_list_size; i++) {
+ if (codepoint <= libcmap_no_data_range_list[i].last) {
+ if (libcmap_no_data_range_list[i].first > codepoint)
+ break;
+ if (!data_out)
+ return 1;
+ data = libcmap_find_codepoint_data(libcmap_no_data_range_list[i].first);
+ switch ((int)data->general_category) {
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_CONTROL: metalabel = "control"; goto have_metalabel;
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_SURROGATE: metalabel = "surrogate"; goto have_metalabel;
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_PRIVATE_USE: metalabel = "private-use"; goto have_metalabel;
+ default:
+ namelen = strlen(data->name);
+ namelen -= sizeof(", First") - 1u;
+ if (namelen + 1u > *bufsizep) {
+ *bufsizep = namelen + 1u;
+ errno = ERANGE;
+ return -1;
+ }
+ memcpy(buffer, data->name, namelen - 1u);
+ ((char *)buffer)[namelen - 1u] = '>';
+ ((char *)buffer)[namelen] = '\0';
+ break;
+
+ have_metalabel:
+ if (construct_codepoint_label(metalabel, codepoint, buffer, bufsizep))
+ return -1;
+ break;
+ }
+ *data_out = *data;
+ data_out->name = buffer;
+ return 1;
+ }
+ }
+
+ data = libcmap_find_codepoint_data(codepoint);
+ if (!data) {
+ if (data_out) {
+ if (construct_codepoint_label("reserved", codepoint, buffer, bufsizep))
+ return -1;
+ data_out->name = buffer;
+ data_out->general_category = LIBCMAP_GENERAL_CATEGORY_OTHER_NOT_ASSIGNED;
+ data_out->noncharacter = 0u;
+ }
+ return 1;
+ }
+
+ if (data_out) {
+ if (data->name[0u] == '<') {
+ if (construct_codepoint_label(data->name, codepoint, buffer, bufsizep))
+ return -1;
+ *data_out = *data;
+ data_out->name = buffer;
+ } else {
+ *data_out = *data;
+ }
+ }
+
+ return 1;
+}