From 62a992b7ac7576b4b13dd714b87e67ca6b177009 Mon Sep 17 00:00:00 2001 From: Adrian Cochrane Date: Thu, 1 Feb 2024 15:20:47 +1300 Subject: [PATCH] Encode & decode FontConfig data on C side. --- cbits/transcode.c | 334 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) diff --git a/cbits/transcode.c b/cbits/transcode.c index 52469fb..5b3d864 100644 --- a/cbits/transcode.c +++ b/cbits/transcode.c @@ -1,8 +1,78 @@ #include "cmp.h" #include #include +#include +#include + +FcStrSet *decodeStrSet(cmp_ctx_t *bytes) { + if (bytes == NULL) return NULL; + + uint32_t size; + if (!cmp_read_array(bytes, &size)) return NULL; + + FcStrSet *ret = FcStrSetCreate(); + if (ret == NULL) return NULL; + + for (uint32_t i = 0; i < size; i++) { + char text[512]; // What's the appropriate size here? + uint32_t str_size = 512; + if (!cmp_read_str(bytes, text, &str_size)) goto fail; + if (!FcStrSetAdd(ret, text)) goto fail; + } + return ret; +fail: + FcStrSetDestroy(ret); + return NULL; +} + +FcStrSet *decodeFileSet(cmp_ctx_t *bytes) { + if (bytes == NULL) return NULL; + + uint32_t size; + if (!cmp_read_array(bytes, &size)) return NULL; + + FcStrSet *ret = FcStrSetCreate(); + if (ret == NULL) return NULL; + + for (uint32_t i = 0; i < size; i++) { + char text[512]; // What's the appropriate size here? + uint32_t str_size = 512; + if (!cmp_read_str(bytes, text, &str_size)) goto fail; + if (!FcStrSetAddFilename(ret, text)) goto fail; + } + return ret; +fail: + FcStrSetDestroy(ret); + return NULL; +} + +bool encodeStrSet(cmp_ctx_t *bytes, FcStrSet *data) { + if (bytes == NULL || data == NULL) return false; + bool ret = false; + + FcStrList *iter = FcStrListCreate(data); + if (iter == NULL) return false; + + uint32_t size = 0; + FcStrListFirst(iter); + while (FcStrListNext(iter) != NULL) size++; + if (!cmp_write_array(bytes, size)) goto exit; + + FcStrListFirst(iter); + char *text = FcStrListNext(iter); + while (text != NULL) { + if (!cmp_write_str(bytes, text, strlen(text))) goto exit; + text = FcStrListNext(iter); + } + ret = true; +exit: + FcStrListDone(iter); + return ret; +} FcCharSet *decodeCharSet(cmp_ctx_t *bytes) { + if (bytes == NULL) return NULL; + uint32_t size; if (!cmp_read_array(bytes, &size)) return NULL; @@ -23,6 +93,8 @@ fail: } bool encodeCharSet(cmp_ctx_t *bytes, FcCharSet *data) { + if (bytes == NULL || data == NULL) return false; + FcChar32 size = FcCharSetCount(data); FcChar32 count = 0; // For validation if (!cmp_write_array(bytes, size)) return false; @@ -40,3 +112,265 @@ bool encodeCharSet(cmp_ctx_t *bytes, FcCharSet *data) { assert(size == count); return true; } + +FcLangSet *decodeLangSet(cmp_ctx_t *bytes) { + if (bytes == NULL) return NULL; + uint32_t size; + if (!cmp_read_array(bytes, &size)) return NULL; + + FcLangSet *ret = FcLangSetCreate(); + if (ret == NULL) return NULL; + for (uint32_t i = 0; i < size; i++) { + char lang[10]; + uint32_t str_size = 10; + if (!cmp_read_str(bytes, lang, &str_size)) goto fail; + char *lang2 = FcLangNormalize(lang); + if (lang2 == NULL) goto fail; + if (!FcLangSetAdd(ret, lang2)) goto fail; + free(lang2); + } + return ret; +fail: + FcLangSetDestroy(ret); + return NULL; +} + +bool encodeLangSet(cmp_ctx_t *bytes, FcLangSet *data) { + if (bytes == NULL || data == NULL) return false; + FcStrSet *langs = FcLangSetGetLangs(data); + if (langs == NULL) return false; + bool ret = encodeStrSet(bytes, langs); + FcStrSetDestroy(langs); + return ret; +} + +FcObjectSet *decodeObjectSet(cmp_ctx_t *bytes) { + if (bytes == NULL) return NULL; + + uint32_t size; + if (!cmp_read_array(bytes, &size)) return NULL; + + FcObjectSet *ret = FcObjectSetCreate(); + for (uint32_t i = 0; i < size; i++) { + char object[20]; + uint32_t o_size = 20; + if (!cmp_read_str(bytes, lang, &str_size)) goto fail; + if (!FcObjectSetAdd(ret, object)) goto fail; + } + return ret; +fail: + FcObjectSetDestroy(ret); + return NULL; +} + +// No corresponding objectset encoder. + +FcRange *decodeRange(cmp_ctx_t *bytes) { + if (bytes == NULL) return NULL; + + uint32_t size; + if (!cmp_read_map(bytes, &size)) return NULL; + + double range[2]; + for (uint32_t i = 0; i < size; i++) { + uint32_t j; + if (!cmp_read_uint(bytes, &j)) return NULL; + if (!cmp_read_double(bytes, &range[j])) return NULL; + } + return FcCreateDouble(range[0], range[1]); +} + +bool encodeRange(cmp_ctx_t *bytes, FcRange *data) { + if (bytes == NULL || data == NULL) return false; + + double begin, end; + if (!FcRangeGetDouble(data, &begin, &end)) return false; + + if (!cmp_write_map(bytes, 2)) return false; + if (!cmp_write_uint(bytes, 0)) return false; + if (!cmp_write_double(bytes, begin)) return false; + if (!cmp_write_uint(bytes, 1)) return false; + if (!cmp_write_double(bytes, end)) return false; + return true; +} + +FcMatrix *decodeMatrix(cmp_ctx_t *bytes) { + if (bytes == NULL) return NULL; + + uint32_t size; + if (!cmp_read_array(bytes, &size) || size != 4) return NULL; + + FcMatrix *ret = malloc(sizeof(FcMatrix)); + if (!cmp_read_double(bytes, &ret->xx)) goto fail; + if (!cmp_read_double(bytes, &ret->xy)) goto fail; + if (!cmp_read_double(bytes, &ret->yx)) goto fail; + if (!cmp_read_double(bytes, &ret->yy)) goto fail; + return ret; +fail: + free(ret); + return NULL; +} + +bool encodeMatrix(cmp_ctx_t *bytes, FcMatrix *data) { + if (bytes == NULL || data == NULL) return NULL; + + if (!cmp_write_array(bytes, 4)) return false; + if (!cmp_write_double(bytes, data->xx)) return false; + if (!cmp_write_double(bytes, data->xy)) return false; + if (!cmp_write_double(bytes, data->yx)) return false; + if (!cmp_write_double(bytes, data->yy)) return false; + return true; +} + +bool decodeValue(cmp_ctx_t *bytes, FcValue *out) { + if (bytes == NULL || out == NULL) return false; + + if (cmp_read_nil(bytes)) out->type = FcTypeVoid; + else if (cmp_read_int(bytes, &out->u.i)) out->type = FcTypeInteger; + else if (cmp_read_double(bytes, &out->u.d)) out->type = FcTypeDouble; + else if (cmp_read_string(bytes, &out->u.s, NULL)) out->type = FcTypeString; + else if (cmp_read_bool(bytes, &out->u.b)) out->type = FcTypeBool; + else if ((out->u.m = decodeMatrix(bytes)) != NULL) out->type = FcTypeMatrix; + else if ((out->u.c = decodeCharSet(bytes)) != NULL) out->type = FcTypeCharSet; + // Not supporting FcTypeFcFace + else if ((out->u.l = decodeLangSet(bytes)) != NULL) out->type = FcTypeLangSet; + else if ((out->u.r = decodeRange(bytes)) != NULL) out->type = FcTypeRange; + else return false; + return true; +} + +bool encodeValue(cmp_ctx_t *bytes, FcValue *data) { + if (bytes == NULL || data == NULL) return false; + + switch (data->type) { + case FcTypeVoid: + return cmp_write_nil(bytes); + case FcTypeInteger: + return cmp_write_int(bytes, data->u.i); + case FcTypeDouble: + return cmp_write_double(bytes, data->u.d); + case FcTypeString: + return cmp_write_string(bytes, data->u.s, strlen(data->u.s)); + case FcTypeBool: + return cmp_write_bool(bytes, data->u.b); + case FcTypeMatrix: + return encodeMatrix(bytes, data->u.m); + case FcTypeCharSet: + return encodeCharSet(bytes, data->u.c); + case FcTypeFcFace: + return true; // Not supporting this yet... + case FcTypeLangSet: + return encodeLangSet(bytes, data->u.l); + case FcTypeRange: + return encodeRange(bytes, data->u.r); + default: + return false; + } +} + +FcPattern *decodePattern(cmp_ctx_t *bytes) { + if (bytes == NULL) return NULL; + + uint32_t size; + if (!cmp_read_map(bytes, &size)) return NULL; + + FcPattern *ret = FcPatternCreate(); + for (uint32_t i = 0; i < size; i++) { + char object[20]; + uint32_t osize = 20; + if (!cmp_read_string(bytes, object, &osize)) goto fail; + uint32_t vsize; + if (!cmp_read_array(bytes, &vsize)) goto fail; + for (uint32 j = 0; j < vsize; j++) { + uint32_t tsize; + if (!cmp_read_array(bytes, &tsize) || tsize != 2) goto fail; + bool is_strong = false; + if (cmp_read_bool(bytes, &is_weak)) {} + else if (cmp_read_nil(bytes)) {} + else goto fail; + FcValue val; + if (!decodeValue(bytes, &val)) goto fail; + if (is_strong) { + if (!FcPatternAdd(bytes, object, value, true)) goto fail; + } else { + if (!FcPatternAddWeak(bytes, object, value, true)) goto fail; + } + } + } + return ret; +fail: + FcPatternDestroy(ret); + return NULL; +} + +bool encodePattern(cmp_ctx_t *bytes, FcPattern *data) { + if (bytes == NULL || data == NULL) return false; + + int size = FcPatternObjectCount(data); + if (!cmp_write_map(bytes, &size)) return false; + + FcPatternIter iter; + FcPatternIterStart(data, &iter); + int count = 0; + while (FcPatternIterNext(data, &iter)) { + count++; + char *obj = FcPatternIterGetObject(data, &iter); + if (!cmp_write_string(bytes, obj, strlen(obj))) return false; + int nvalues = FcPatternIterValueCount(data, &iter); + if (!cmp_write_array(bytes, nvalues)) return false; + for (int j = 0; j < nvalues; j++) { + FcValue val; + FcValueBinding weight; + if (FcPatternIterGetValue(data, &iter, j, &val, &weight) != FcResultMatch) + return false; + + if (!cmp_write_array(bytes, 2)) return false; + switch (weight) { + case FcValueBindingWeak: + if (!cmp_write_bool(bytes, false)) return false; + break; + case FcValueBindingStrong: + if (!cmp_write_bool(bytes, true)) return false; + break; + case FcValueBindingSame: + if (!cmp_write_nil(bytes)) return false; + break; + default: + return false; + } + if (!encodeValue(bytes, &val)) return false; + } + } + assert(size == count); + return true; +} + +FcFontSet *decodeFontSet(cmp_ctx_t *bytes) { + if (bytes == NULL) return NULL; + + uint32_t size; + if (!cmp_read_array(bytes, &size)) return NULL; + + FcFontSet *ret = FcFontSetCreate(); + if (ret == NULL) return NULL; + + for (uint32_t i = 0; i < size; i++) { + FcPattern *font = decodePattern(bytes); + if (font == NULL) goto fail; + if (!FcFontSetAdd(ret, font)) goto fail; + } + return ret; +fail: + FcFontSetDestroy(ret); + return NULL; +} + +bool encodeFontSet(cmp_ctx_t *bytes, FcFontSet *data) { + if (bytes == NULL || data == NULL) return NULL; + + if (!cmp_write_array(bytes, data->nfont)) return false; + for (int i = 0; i < data->nfont; i++) { + if (!encodePattern(bytes, data->fonts[i])) return false; + } + return true; +} -- 2.30.2