~alcinnz/fontconfig-pure

62a992b7ac7576b4b13dd714b87e67ca6b177009 — Adrian Cochrane a year ago 35586a3
Encode & decode FontConfig data on C side.
1 files changed, 334 insertions(+), 0 deletions(-)

M cbits/transcode.c
M cbits/transcode.c => cbits/transcode.c +334 -0
@@ 1,8 1,78 @@
#include "cmp.h"
#include <fontconfig/fontconfig.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>

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;
}