#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; FcCharSet *ret = FcCharSetCreate(); if (ret == NULL) return NULL; FcChar32 prev = 0; for (uint32_t i = 0; i < size; i++) { uint32_t x; if (!cmp_read_uint(bytes, &x)) goto fail; prev += x; if (!FcCharSetAddChar(ret, prev)) goto fail; } return ret; fail: FcCharSetDestroy(ret); return NULL; } 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; FcChar32 map[FC_CHARSET_MAP_SIZE]; FcChar32 next; FcChar32 c = FcCharSetFirstPage(data, map, &next); FcChar32 prev = 0; while (c != FC_CHARSET_DONE) { if (!cmp_write_uinteger(bytes, c - prev)) return false; prev = c; count++; c = FcCharSetNextPage(data, map, &next); } 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; }