diff options
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/table/name.c')
-rw-r--r-- | Build/source/texk/web2c/mfluadir/otfcc/lib/table/name.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/table/name.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/name.c new file mode 100644 index 00000000000..9f579932564 --- /dev/null +++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/name.c @@ -0,0 +1,198 @@ +#include "name.h" + +#include "support/util.h" +#include "support/unicodeconv/unicodeconv.h" + +#ifndef MAIN_VER +#define MAIN_VER 0 +#endif +#ifndef SECONDARY_VER +#define SECONDARY_VER 0 +#endif +#ifndef PATCH_VER +#define PATCH_VER 0 +#endif + +#define COPYRIGHT_LEN 32 + +static void nameRecordDtor(otfcc_NameRecord *entry) { + DELETE(sdsfree, entry->nameString); +} +caryll_standardType(otfcc_NameRecord, otfcc_iNameRecord, nameRecordDtor); +caryll_standardVectorImpl(table_name, otfcc_NameRecord, otfcc_iNameRecord, table_iName); + +static bool shouldDecodeAsUTF16(const otfcc_NameRecord *record) { + return (record->platformID == 0) // Unicode, all + || (record->platformID == 2 && record->encodingID == 1) // ISO, 1 + || (record->platformID == 3 && // Microsoft, 0, 1, 10 + (record->encodingID == 0 || record->encodingID == 1 || record->encodingID == 10)); +} +static bool shouldDecodeAsBytes(const otfcc_NameRecord *record) { + return record->platformID == 1 && record->encodingID == 0 && + record->languageID == 0; // Mac Roman English - I hope +} + +table_name *otfcc_readName(const otfcc_Packet packet, const otfcc_Options *options) { + FOR_TABLE(OTFCC_CHR('n','a','m','e'), table) { + table_name *name = NULL; + font_file_pointer data = table.data; + + uint32_t length = table.length; + if (length < 6) goto TABLE_NAME_CORRUPTED; + uint32_t count = read_16u(data + 2); + uint32_t stringOffset = read_16u(data + 4); + if (length < 6 + 12 * count) goto TABLE_NAME_CORRUPTED; + + name = table_iName.create(); + + for (uint16_t j = 0; j < count; j++) { + otfcc_NameRecord record; + record.platformID = read_16u(data + 6 + j * 12); + record.encodingID = read_16u(data + 6 + j * 12 + 2); + record.languageID = read_16u(data + 6 + j * 12 + 4); + record.nameID = read_16u(data + 6 + j * 12 + 6); + record.nameString = NULL; + uint16_t length = read_16u(data + 6 + j * 12 + 8); + uint16_t offset = read_16u(data + 6 + j * 12 + 10); + + if (shouldDecodeAsBytes(&record)) { + // Mac Roman. Note that this is not very correct, but works for most fonts + sds nameString = sdsnewlen(data + stringOffset + offset, length); + record.nameString = nameString; + } else if (shouldDecodeAsUTF16(&record)) { + sds nameString = utf16be_to_utf8(data + stringOffset + offset, length); + record.nameString = nameString; + } else { + size_t len = 0; + uint8_t *buf = base64_encode(data + stringOffset + offset, length, &len); + record.nameString = sdsnewlen(buf, len); + FREE(buf); + } + table_iName.push(name, record); + } + return name; + TABLE_NAME_CORRUPTED: + logWarning("table 'name' corrupted.\n"); + if (name) { DELETE(table_iName.free, name); } + } + return NULL; +} + +void otfcc_dumpName(const table_name *name, json_value *root, const otfcc_Options *options) { + if (!name) return; + loggedStep("name") { + json_value *_name = json_array_new(name->length); + for (uint16_t j = 0; j < name->length; j++) { + otfcc_NameRecord *r = &(name->items[j]); + json_value *record = json_object_new(5); + json_object_push(record, "platformID", json_integer_new(r->platformID)); + json_object_push(record, "encodingID", json_integer_new(r->encodingID)); + json_object_push(record, "languageID", json_integer_new(r->languageID)); + json_object_push(record, "nameID", json_integer_new(r->nameID)); + json_object_push( + record, "nameString", + json_string_new_length((uint32_t)sdslen(r->nameString), r->nameString)); + json_array_push(_name, record); + } + json_object_push(root, "name", _name); + } +} +static int name_record_sort(const otfcc_NameRecord *a, const otfcc_NameRecord *b) { + if (a->platformID != b->platformID) return a->platformID - b->platformID; + if (a->encodingID != b->encodingID) return a->encodingID - b->encodingID; + if (a->languageID != b->languageID) return a->languageID - b->languageID; + return a->nameID - b->nameID; +} +table_name *otfcc_parseName(const json_value *root, const otfcc_Options *options) { + table_name *name = table_iName.create(); + json_value *table = NULL; + if ((table = json_obj_get_type(root, "name", json_array))) { + loggedStep("name") { + + for (uint32_t j = 0; j < table->u.array.length; j++) { + if (!(table->u.array.values[j] && table->u.array.values[j]->type == json_object)) + continue; + json_value *_record = table->u.array.values[j]; + if (!json_obj_get_type(_record, "platformID", json_integer)) { + logWarning("Missing or invalid platformID for name entry %d\n", j); + continue; + } + if (!json_obj_get_type(_record, "encodingID", json_integer)) { + logWarning("Missing or invalid encodingID for name entry %d\n", j); + continue; + } + if (!json_obj_get_type(_record, "languageID", json_integer)) { + logWarning("Missing or invalid languageID for name entry %d\n", j); + continue; + } + if (!json_obj_get_type(_record, "nameID", json_integer)) { + logWarning("Missing or invalid nameID for name entry %d\n", j); + continue; + } + if (!json_obj_get_type(_record, "nameString", json_string)) { + logWarning("Missing or invalid name string for name entry %d\n", j); + continue; + } + otfcc_NameRecord record; + record.platformID = json_obj_getint(_record, "platformID"); + record.encodingID = json_obj_getint(_record, "encodingID"); + record.languageID = json_obj_getint(_record, "languageID"); + record.nameID = json_obj_getint(_record, "nameID"); + + json_value *str = json_obj_get_type(_record, "nameString", json_string); + record.nameString = sdsnewlen(str->u.string.ptr, str->u.string.length); + table_iName.push(name, record); + } + + table_iName.sort(name, name_record_sort); + } + } + return name; +} +caryll_Buffer *otfcc_buildName(const table_name *name, const otfcc_Options *options) { + if (!name) return NULL; + caryll_Buffer *buf = bufnew(); + bufwrite16b(buf, 0); + bufwrite16b(buf, name->length); + bufwrite16b(buf, 0); // fill later + caryll_Buffer *strings = bufnew(); + for (uint16_t j = 0; j < name->length; j++) { + otfcc_NameRecord *record = &(name->items[j]); + bufwrite16b(buf, record->platformID); + bufwrite16b(buf, record->encodingID); + bufwrite16b(buf, record->languageID); + bufwrite16b(buf, record->nameID); + size_t cbefore = strings->cursor; + if (shouldDecodeAsUTF16(record)) { + size_t words; + uint8_t *u16 = utf8toutf16be(record->nameString, &words); + bufwrite_bytes(strings, words, u16); + FREE(u16); + } else if (shouldDecodeAsBytes(record)) { + bufwrite_bytes(strings, sdslen(record->nameString), (uint8_t *)record->nameString); + } else { + size_t length; + uint8_t *decoded = + base64_decode((uint8_t *)record->nameString, sdslen(record->nameString), &length); + bufwrite_bytes(strings, length, decoded); + FREE(decoded); + } + size_t cafter = strings->cursor; + bufwrite16b(buf, cafter - cbefore); + bufwrite16b(buf, cbefore); + } + + // write copyright info + sds copyright = + sdscatprintf(sdsempty(), "-- By OTFCC %d.%d.%d --", MAIN_VER, SECONDARY_VER, PATCH_VER); + sdsgrowzero(copyright, COPYRIGHT_LEN); + bufwrite_bytes(strings, COPYRIGHT_LEN, (uint8_t *)copyright); + sdsfree(copyright); + + size_t stringsOffset = buf->cursor; + bufwrite_buf(buf, strings); + bufseek(buf, 4); + bufwrite16b(buf, stringsOffset); + buffree(strings); + return buf; +} |