From ec65be5f2b04095cca777bb7168553306c268cb4 Mon Sep 17 00:00:00 2001 From: handa Date: Fri, 6 Dec 2002 13:23:28 +0000 Subject: [PATCH] *** empty log message *** --- configure.ac | 1 + example/Makefile.am | 9 +- example/otfdraw.c | 11 +- example/otfdump.c | 10 + src/Makefile.am | 6 +- src/config.h.in | 3 + src/otf-open.c | 1878 ------------------------------------------------- src/otf-proc.c | 584 ---------------- src/otf-util.c | 50 -- src/otf-util.h | 40 -- src/otf.h | 26 +- src/otfdrive.c | 587 ++++++++++++++++ src/otfopen.c | 1940 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/otfutil.c | 50 ++ src/otfutil.h | 5 + 15 files changed, 2624 insertions(+), 2576 deletions(-) delete mode 100644 src/otf-open.c delete mode 100644 src/otf-proc.c delete mode 100644 src/otf-util.c delete mode 100644 src/otf-util.h create mode 100644 src/otfdrive.c create mode 100644 src/otfopen.c create mode 100644 src/otfutil.c create mode 100644 src/otfutil.h diff --git a/configure.ac b/configure.ac index f6e4fa3..ea84dba 100644 --- a/configure.ac +++ b/configure.ac @@ -8,6 +8,7 @@ AC_PROG_CC AC_PROG_LIBTOOL # Checks for libraries. +AC_PATH_XTRA # Checks for header files. AC_HEADER_STDC diff --git a/example/Makefile.am b/example/Makefile.am index 4168c53..ad639e9 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -1,12 +1,17 @@ bin_PROGRAMS = otfdump otfdraw INCLUDES = `freetype-config --cflags` +CommonLDADD = ${top_builddir}/src/libotf.la +CommonLDFLAGS = -all-static + otfdump_SOURCE = otfdump.c -otfdump_LDFLAGS = -lotf +otfdump_LDADD = ${CommonLDADD} +otfdump_LDFLAGS = ${CommonLDFLAGS} otfdraw_SOURCE = otfdraw -otfdraw_LDFLAGS = `freetype-config --libs` -lotf -L/usr/X11R6/lib -lX11 +otfdraw_LDADD = ${CommonLDADD} +otfdraw_LDFLAGS = `freetype-config --libs` ${X_LIBS} ${X_PRE_LIBS} -lX11 ${CommonLDFLAGS} # We should not install any programs in this directory. diff --git a/example/otfdraw.c b/example/otfdraw.c index 8f5bf65..433b781 100644 --- a/example/otfdraw.c +++ b/example/otfdraw.c @@ -1,5 +1,6 @@ #include #include +#include #include "otf.h" @@ -76,9 +77,11 @@ main (int argc, char **argv) } otf = otf_open (argv[1]); - + if (! otf) + otf_perror ("otfdraw:"); gstring.size = 10; - gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * 10); + gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * 30); + memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * 30); gstring.used = 0; #if 0 gstring.glyphs[gstring.used++].c = 0x93F; @@ -152,6 +155,10 @@ main (int argc, char **argv) FT_Load_Glyph (face, gstring.glyphs[i].glyph_id, FT_LOAD_RENDER | FT_LOAD_MONOCHROME); + if (gstring.glyphs[i].positioning_type) + { + printf ("%d:%d\n", i, gstring.glyphs[i].positioning_type); + } draw_bitmap (face, x + face->glyph->bitmap_left, y - face->glyph->bitmap_top); diff --git a/example/otfdump.c b/example/otfdump.c index 2918d7d..bacf528 100644 --- a/example/otfdump.c +++ b/example/otfdump.c @@ -725,6 +725,8 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type, static void dump_gpos_table (int indent, OTF_GPOS *gpos) { + if (! gpos) + return; IPRINT ("(GPOS"); indent++; IPRINT ("(Header"); @@ -824,6 +826,8 @@ dump_lig_caret_list (int indent, OTF_LigCaretList *list) static void dump_gdef_table (int indent, OTF_GDEF *gdef) { + if (! gdef) + return; IPRINT ("(GDEF"); indent++; dump_gdef_header (indent, &gdef->header); @@ -989,6 +993,12 @@ main (int argc, char **argv) } otf = otf_open (argv[1]); + otf_get_table (otf, otf_tag ("head")); + otf_get_table (otf, otf_tag ("name")); + otf_get_table (otf, otf_tag ("cmap")); + otf_get_table (otf, otf_tag ("GDEF")); + otf_get_table (otf, otf_tag ("GSUB")); + otf_get_table (otf, otf_tag ("GPOS")); otf_dump (otf); otf_close (otf); exit (0); diff --git a/src/Makefile.am b/src/Makefile.am index 7db8e1f..832226c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,8 +2,8 @@ lib_LTLIBRARIES = libotf.la libotf_la_SOURCES = \ otf.h \ - otf-util.h otf-util.c \ - otf-open.c \ - otf-proc.c + otfutil.h otfutil.c \ + otfopen.c \ + otfdrive.c include_HEADERS = otf.h diff --git a/src/config.h.in b/src/config.h.in index 46c34fe..d2fdb05 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -82,3 +82,6 @@ /* Version number of package */ #undef VERSION + +/* Define to 1 if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING diff --git a/src/otf-open.c b/src/otf-open.c deleted file mode 100644 index 6d0e33f..0000000 --- a/src/otf-open.c +++ /dev/null @@ -1,1878 +0,0 @@ -#include -#include -#include - -#include "otf.h" -#include "otf-util.h" - -/* OTF_Stream - - Example of typical usage of OTF_Stream. - - { - OTF_Stream *stream; - OTF_StreamState state; - int offset, nbytes; - - OPEN_STREAM (_FILE_NAME_, stream); - if (! stream) - _ERROR_; - SETUP_STREAM (stream, fp, 0, 256, _NAME_); - offset = READ_OFFSET (stream); - nbytes = READ_ULONG (stream); - SETUP_STREAM (stream, fp, offset, nbytes, _NAME2_); - ...; - CLOSE_STREAM (stream); - } - -*/ - -typedef long OTF_StreamState; - -OTF_Stream * -make_stream () -{ - OTF_Stream *stream; - char *errfmt = "stream creation%s"; - void *errret = NULL; - - OTF_CALLOC (stream, 1, ""); - return stream; -} - -int -setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes, - char *name) -{ - char *errfmt = "stream setup for %s"; - int errret = -1; - - stream->name = name; - stream->pos = 0; - if (stream->allocated < nbytes) - { - unsigned char *buf = (unsigned char *) malloc (nbytes); - - if (! buf) - OTF_ERROR (OTF_ERROR_MEMORY, stream->name); - if (stream->buf) - free (stream->buf); - stream->buf = buf; - stream->allocated = nbytes; - } - stream->bufsize = nbytes; - if (fseek (fp, offset, SEEK_SET) < 0) - OTF_ERROR (OTF_ERROR_FILE, stream->name); - if (fread (stream->buf, 1, nbytes, fp) != nbytes) - OTF_ERROR (OTF_ERROR_FILE, stream->name); - return 0; -} - - -void -free_stream (OTF_Stream *stream) -{ - free (stream->buf); - free (stream); -} - -#define SAVE_STREAM(stream, state) ((state) = (stream)->pos) -#define RESTORE_STREAM(stream, state) ((stream)->pos = (state)) -#define SEEK_STREAM(stream, offset) ((stream)->pos = (offset)) - -#define STREAM_CHECK_SIZE(stream, size) \ - if ((stream)->pos + (size) > (stream)->bufsize) \ - { \ - char *errfmt = "buffer overrun in %s"; \ - \ - OTF_ERROR (OTF_ERROR_TABLE, (stream)->name); \ - return errret; \ - } \ - else - - -#define READ_USHORT(stream, var) \ - do { \ - STREAM_CHECK_SIZE ((stream), 2); \ - (var) = (((stream)->buf[(stream)->pos] << 8) \ - | (stream)->buf[(stream)->pos + 1]); \ - (stream)->pos += 2; \ - } while (0) - -#define READ_SHORT(stream, var) \ - do { \ - STREAM_CHECK_SIZE ((stream), 2); \ - (var) = (short) (((stream)->buf[(stream)->pos] << 8) \ - | (stream)->buf[(stream)->pos + 1]); \ - (stream)->pos += 2; \ - } while (0) - -#define READ_ULONG(stream, var) \ - do { \ - STREAM_CHECK_SIZE ((stream), 4); \ - (var) = (((stream)->buf[(stream)->pos] << 24) \ - | ((stream)->buf[(stream)->pos + 1] << 16) \ - | ((stream)->buf[(stream)->pos + 2] << 8) \ - | (stream)->buf[(stream)->pos + 3]); \ - (stream)->pos += 4; \ - } while (0) - -#define READ_LONG(stream, var) \ - do { \ - STREAM_CHECK_SIZE ((stream), 4); \ - (var) = (int) (((stream)->buf[(stream)->pos] << 24) \ - | ((stream)->buf[(stream)->pos + 1] << 16) \ - | ((stream)->buf[(stream)->pos + 2] << 8) \ - | (stream)->buf[(stream)->pos + 3]); \ - (stream)->pos += 4; \ - } while (0) - - -#define READ_FIXED(stream, fixed) \ - do { \ - READ_USHORT ((stream), (fixed).high); \ - READ_USHORT ((stream), (fixed).low); \ - } while (0) - - -#define READ_BYTES(stream, p, nbytes) \ - do { \ - STREAM_CHECK_SIZE ((stream), (nbytes)); \ - memcpy ((p), (stream)->buf + (stream)->pos, (nbytes)); \ - (stream)->pos += (nbytes); \ - } while (0) - - -#define READ_TAG READ_ULONG -#define READ_OFFSET READ_USHORT -#define READ_UINT16 READ_USHORT -#define READ_INT16 READ_SHORT -#define READ_GLYPHID READ_USHORT - - - -int -read_offset_table (OTF_Stream *stream, OTF_OffsetTable *table) -{ - int errret = -1; - - READ_FIXED (stream, table->sfnt_version); - READ_USHORT (stream, table->numTables); - READ_USHORT (stream, table->searchRange); - READ_USHORT (stream, table->enterSelector); - READ_USHORT (stream, table->rangeShift); - return 0; -} - -static OTF_Tag -read_table_directory (OTF_Stream *stream, OTF_TableDirectory *table) -{ - int errret = 0; - OTF_Tag tag; - - READ_TAG (stream, tag); - table->tag = tag; - table->name[0] = tag >> 24; - table->name[1] = (tag >> 16) & 0xFF; - table->name[0] = (tag >> 8) & 0xFF; - table->name[0] = tag >> 8; - table->name[0] = '\0'; - READ_ULONG (stream, table->checkSum); - READ_ULONG (stream, table->offset); - READ_ULONG (stream, table->length); - return tag; -} - - - -static void * -read_head_table (OTF_Stream *stream) -{ - char *errfmt = "head%s"; - void *errret = NULL; - OTF_head *head; - - OTF_CALLOC (head, 1, ""); - READ_FIXED (stream, head->TableVersionNumber); - READ_FIXED (stream, head->fontRevision); - READ_ULONG (stream, head->checkSumAdjustment); - READ_ULONG (stream, head->magicNumber); - READ_USHORT (stream, head->flags); - READ_USHORT (stream, head->unitsPerEm); - - return head; -} - -static void -free_head_table (OTF_head *head) -{ - free (head); -} - - - -static int -read_script_list (OTF_Stream *stream, long offset, OTF_ScriptList *list) -{ - char *errfmt = "Script List%s"; - int errret = -1; - int i, j, k; - - SEEK_STREAM (stream, offset); - READ_USHORT (stream, list->ScriptCount); - OTF_CALLOC (list->Script, list->ScriptCount, ""); - - for (i = 0; i < list->ScriptCount; i++) - { - READ_TAG (stream, list->Script[i].ScriptTag); - READ_OFFSET (stream, list->Script[i].offset); - } - for (i = 0; i < list->ScriptCount; i++) - { - OTF_Script *script = list->Script + i; - long script_offset = offset + script->offset; - - SEEK_STREAM (stream, script_offset); - READ_OFFSET (stream, script->DefaultLangSysOffset); - READ_USHORT (stream, script->LangSysCount); - OTF_MALLOC (script->LangSysRecord, script->LangSysCount, " (LangSys)"); - OTF_CALLOC (script->LangSys, script->LangSysCount, " (LangSys)"); - for (j = 0; j < script->LangSysCount; j++) - { - READ_TAG (stream, script->LangSysRecord[j].LangSysTag); - READ_OFFSET (stream, script->LangSysRecord[j].LangSys); - } - - if (script->DefaultLangSysOffset) - { - OTF_LangSys *langsys = &script->DefaultLangSys; - - SEEK_STREAM (stream, script_offset + script->DefaultLangSysOffset); - READ_OFFSET (stream, langsys->LookupOrder); - READ_USHORT (stream, langsys->ReqFeatureIndex); - READ_USHORT (stream, langsys->FeatureCount); - OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount, - " (FeatureIndex)"); - for (k = 0; k < langsys->FeatureCount; k++) - READ_USHORT (stream, langsys->FeatureIndex[k]); - } - - for (j = 0; j < script->LangSysCount; j++) - { - OTF_LangSys *langsys = script->LangSys + j; - - SEEK_STREAM (stream, - script_offset + script->LangSysRecord[j].LangSys); - READ_OFFSET (stream, langsys->LookupOrder); - READ_USHORT (stream, langsys->ReqFeatureIndex); - READ_USHORT (stream, langsys->FeatureCount); - OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount, - " (FeatureIndex)"); - for (k = 0; k < langsys->FeatureCount; k++) - READ_USHORT (stream, langsys->FeatureIndex[k]); - } - } - - return 0; -} - -static int -read_feature_list (OTF_Stream *stream, long offset, OTF_FeatureList *list) -{ - char *errfmt = "Feature List%s"; - int errret = -1; - int i, j; - - READ_UINT16 (stream, list->FeatureCount); - OTF_CALLOC (list->Feature, list->FeatureCount, ""); - for (i = 0; i < list->FeatureCount; i++) - { - READ_TAG (stream, list->Feature[i].FeatureTag); - READ_OFFSET (stream, list->Feature[i].offset); - } - for (i = 0; i < list->FeatureCount; i++) - { - OTF_Feature *feature = list->Feature + i; - - SEEK_STREAM (stream, offset + feature->offset); - READ_OFFSET (stream, feature->FeatureParams); - READ_UINT16 (stream, feature->LookupCount); - OTF_MALLOC (feature->LookupListIndex, feature->LookupCount, - " (LookupListIndex)"); - for (j = 0; j < feature->LookupCount; j++) - READ_UINT16 (stream, feature->LookupListIndex[j]); - } - - return 0; -} - -static int read_lookup_subtable_gsub (OTF_Stream *stream, long offset, - unsigned type, - OTF_LookupSubTable *subtable); -static int read_lookup_subtable_gpos (OTF_Stream *stream, long offset, - unsigned type, - OTF_LookupSubTable *subtable); - -static int -read_lookup_list (OTF_Stream *stream, long offset, - OTF_LookupList *list, int gsub) -{ - char *errfmt = "Lookup List%s"; - int errret = -1; - int i, j; - - SEEK_STREAM (stream, offset); - READ_UINT16 (stream, list->LookupCount); - OTF_CALLOC (list->Lookup, list->LookupCount, ""); - - for (i = 0; i < list->LookupCount; i++) - READ_OFFSET (stream, list->Lookup[i].offset); - for (i = 0; i < list->LookupCount; i++) - { - OTF_Lookup *lookup = list->Lookup + i; - - SEEK_STREAM (stream, offset + lookup->offset); - READ_UINT16 (stream, lookup->LookupType); - READ_UINT16 (stream, lookup->LookupFlag); - READ_UINT16 (stream, lookup->SubTableCount); - OTF_MALLOC (lookup->SubTableOffset, lookup->SubTableCount, - " (SubTableOffset)"); - OTF_CALLOC (lookup->SubTable, lookup->SubTableCount, - " (SubTable)"); - for (j = 0; j < lookup->SubTableCount; j++) - READ_OFFSET (stream, lookup->SubTableOffset[j]); - if (gsub) - for (j = 0; j < lookup->SubTableCount; j++) - { - long this_offset - = offset + lookup->offset + lookup->SubTableOffset[j]; - - if (read_lookup_subtable_gsub (stream, this_offset, - lookup->LookupType, - lookup->SubTable + j) < 0) - return errret; - } - else - for (j = 0; j < lookup->SubTableCount; j++) - { - long this_offset - = offset + lookup->offset + lookup->SubTableOffset[j]; - - if (read_lookup_subtable_gpos (stream, this_offset, - lookup->LookupType, - lookup->SubTable + j) < 0) - return errret; - } - } - - return 0; -} - - -static int -read_glyph_ids (OTF_Stream *stream, OTF_GlyphID **ids, int minus) -{ - char *errfmt = "GlyphID List%s"; - int errret = -1; - unsigned count; - int i; - - READ_UINT16 (stream, count); - if (! count) - return 0; - OTF_MALLOC (*ids, count, ""); - for (i = 0; i < count + minus; i++) - READ_GLYPHID (stream, (*ids)[i]); - return (int) count; -} - -static unsigned -read_range_record (OTF_Stream *stream, OTF_RangeRecord **record) -{ - char *errfmt = "RangeRecord%s"; - unsigned errret = 0; - unsigned count; - int i; - - READ_UINT16 (stream, count); - if (! count) - return 0; - OTF_MALLOC (*record, count, ""); - for (i = 0; i < count; i++) - { - READ_GLYPHID (stream, (*record)[i].Start); - READ_GLYPHID (stream, (*record)[i].End); - READ_UINT16 (stream, (*record)[i].StartCoverageIndex); - } - return count; -} - - -static int -read_coverage (OTF_Stream *stream, long offset, OTF_Coverage *coverage) -{ - char *errfmt = "Coverage%s"; - int errret = -1; - OTF_StreamState state; - int count; - - READ_OFFSET (stream, coverage->offset); - SAVE_STREAM (stream, state); - SEEK_STREAM (stream, offset + coverage->offset); - READ_UINT16 (stream, coverage->CoverageFormat); - if (coverage->CoverageFormat == 1) - count = read_glyph_ids (stream, &coverage->table.GlyphArray, 0); - else if (coverage->CoverageFormat == 2) - count = read_range_record (stream, &coverage->table.RangeRecord); - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid Format)"); - if (count < 0) - return -1; - coverage->Count = (unsigned) count; - RESTORE_STREAM (stream, state); - return 0; -} - -static int -read_coverage_list (OTF_Stream *stream, long offset, OTF_Coverage **coverage) -{ - char *errfmt = "Coverage List%s"; - int errret = -1; - int count; - int i; - - READ_UINT16 (stream, count); - if (! count) - return 0; - OTF_MALLOC (*coverage, count, ""); - for (i = 0; i < count; i++) - if (read_coverage (stream, offset, (*coverage) + i) < 0) - return -1; - return count; -} - - -static int -read_class_def_without_offset (OTF_Stream *stream, OTF_ClassDef *class) -{ - char *errfmt = "ClassDef%s"; - int errret = -1; - - SEEK_STREAM (stream, class->offset); - READ_UINT16 (stream, class->ClassFormat); - if (class->ClassFormat == 1) - { - READ_GLYPHID (stream, class->f.f1.StartGlyph); - class->f.f1.GlyphCount - = (read_glyph_ids - (stream, (OTF_GlyphID **) &class->f.f1.ClassValueArray, 0)); - if (! class->f.f1.GlyphCount) - return -1; - } - else if (class->ClassFormat == 2) - { - class->f.f2.ClassRangeCount - = (read_range_record - (stream, (OTF_RangeRecord **) &class->f.f2.ClassRangeRecord)); - if (! class->f.f2.ClassRangeCount) - return -1; - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); - return 0; -} - - -static int -read_class_def (OTF_Stream *stream, long offset, OTF_ClassDef *class) -{ - char *errfmt = "ClassDef%s"; - int errret = -1; - OTF_StreamState state; - - READ_OFFSET (stream, class->offset); - SAVE_STREAM (stream, state); - SEEK_STREAM (stream, offset + class->offset); - READ_UINT16 (stream, class->ClassFormat); - if (class->ClassFormat == 1) - { - READ_GLYPHID (stream, class->f.f1.StartGlyph); - class->f.f1.GlyphCount - = (read_glyph_ids - (stream, (OTF_GlyphID **) &class->f.f1.ClassValueArray, 0)); - if (! class->f.f1.GlyphCount) - return -1; - } - else if (class->ClassFormat == 2) - { - class->f.f2.ClassRangeCount - = (read_range_record - (stream, (OTF_RangeRecord **) &class->f.f2.ClassRangeRecord)); - if (! class->f.f2.ClassRangeCount) - return -1; - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); - - RESTORE_STREAM (stream, state); - return 0; -} - -static void -free_class_def (OTF_ClassDef *class) -{ - if (class->ClassFormat == 1) - { - if (class->f.f1.GlyphCount) - free (class->f.f1.ClassValueArray); - } - else if (class->ClassFormat == 2) - { - - } -} - - -static int -read_device_table (OTF_Stream *stream, long offset, OTF_DeviceTable *table) -{ - char *errfmt = "Device Table%s"; - int errret = -1; - - int num, i; - unsigned val; - struct { - int int2 : 2; - int int4 : 4; - int int8 : 8; - } intval; - - SEEK_STREAM (stream, offset + table->offset); - READ_UINT16 (stream, table->StartSize); - READ_UINT16 (stream, table->EndSize); - READ_UINT16 (stream, table->DeltaFormat); - num = table->EndSize - table->StartSize + 1; - OTF_MALLOC (table->DeltaValue, num, ""); - - if (table->DeltaFormat == 1) - for (i = 0; i < num; i++) - { - if ((i % 8) == 0) - READ_UINT16 (stream, val); - intval.int2 = (val >> (14 - (i % 8) * 2)) & 0x03; - table->DeltaValue[i] = intval.int2; - } - else if (table->DeltaFormat == 2) - for (i = 0; i < num; i++) - { - if ((i % 4) == 0) - READ_UINT16 (stream, val); - intval.int4 = (val >> (12 - (i % 4) * 4)) & 0x0F; - table->DeltaValue[i] = intval.int4; - } - else if (table->DeltaFormat == 3) - for (i = 0; i < num; i++) - { - if ((i % 2) == 0) - { - READ_UINT16 (stream, val); - intval.int8 = val >> 8; - table->DeltaValue[i] = intval.int8; - } - else - { - intval.int8 = val >> 8; - table->DeltaValue[i] = intval.int8; - } - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); - return 0; -} - - - -/* GSUB */ - -static void * -read_gsub_table (OTF_Stream *stream) -{ - char *errfmt = "GSUB%s"; - void *errret = NULL; - OTF_GSUB *gsub; - - OTF_CALLOC (gsub, 1, ""); - READ_FIXED (stream, gsub->Version); - READ_OFFSET (stream, gsub->ScriptList.offset); - READ_OFFSET (stream, gsub->FeatureList.offset); - READ_OFFSET (stream, gsub->LookupList.offset); - - if (read_script_list (stream, gsub->ScriptList.offset, - &gsub->ScriptList) < 0 - || read_feature_list (stream, gsub->FeatureList.offset, - &gsub->FeatureList) < 0 - || read_lookup_list (stream, gsub->LookupList.offset, - &gsub->LookupList, 1) < 0) - return NULL; - return gsub; -} - - -static unsigned -read_sequence (OTF_Stream *stream, long offset, OTF_Sequence **seq) -{ - char *errfmt = "Sequence%s"; - unsigned errret = 0; - unsigned count; - int i; - - READ_UINT16 (stream, count); - OTF_MALLOC (*seq, count, ""); - if (! count) - OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - for (i = 0; i < count; i++) - READ_OFFSET (stream, (*seq)[i].offset); - for (i = 0; i < count; i++) - { - SEEK_STREAM (stream, offset + (*seq)[i].offset); - (*seq)[i].GlyphCount = read_glyph_ids (stream, &(*seq)[i].Substitute, 0); - if (! (*seq)[i].GlyphCount) - return 0; - } - return count; -} - -static int -read_ligature (OTF_Stream *stream, long offset, OTF_Ligature **ligature) -{ - char *errfmt = "Ligature%s"; - int errret = -1; - int count; - int i; - - READ_UINT16 (stream, count); - if (! count) - return 0; - OTF_MALLOC (*ligature, count, ""); - for (i = 0; i < count; i++) - READ_OFFSET (stream, (*ligature)[i].offset); - for (i = 0; i < count; i++) - { - SEEK_STREAM (stream, offset + (*ligature)[i].offset); - READ_GLYPHID (stream, (*ligature)[i].LigGlyph); - (*ligature)[i].CompCount - = read_glyph_ids (stream, &(*ligature)[i].Component, -1); - if (! (*ligature)[i].CompCount) - return -1; - } - return count; -} - -static int -read_ligature_set (OTF_Stream *stream, long offset, OTF_LigatureSet **ligset) -{ - char *errfmt = "LigatureSet%s"; - int errret = -1; - int count; - int i; - - READ_UINT16 (stream, count); - if (! count) - return 0; - OTF_MALLOC (*ligset, count, ""); - for (i = 0; i < count; i++) - READ_OFFSET (stream, (*ligset)[i].offset); - for (i = 0; i < count; i++) - { - int lig_count; - - SEEK_STREAM (stream, offset + (*ligset)[i].offset); - lig_count = read_ligature (stream, offset + (*ligset)[i].offset, - &(*ligset)[i].Ligature); - if (lig_count < 0) - return -1; - (*ligset)[i].LigatureCount = (unsigned) lig_count; - } - return count; -} - -static unsigned -read_subst_lookup_record (OTF_Stream *stream, OTF_SubstLookupRecord **record) -{ - char *errfmt = "SubstLookupRecord%s"; - unsigned errret = 0; - unsigned count; - int i; - - READ_UINT16 (stream, count); - if (! count) - OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - OTF_MALLOC (*record, count, ""); - for (i = 0; i < count; i++) - { - READ_UINT16 (stream, (*record)[i].SequenceIndex); - READ_UINT16 (stream, (*record)[i].LookupListIndex); - } - return count; -} - -static unsigned -read_chain_subrule (OTF_Stream *stream, long offset, OTF_ChainSubRule **rule) -{ - char *errfmt = "ChainSubRule%s"; - unsigned errret = 0; - unsigned count; - int i; - - READ_UINT16 (stream, count); - if (! count) - OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - OTF_MALLOC (*rule, count, ""); - for (i = 0; i < count; i++) - READ_OFFSET (stream, (*rule)[i].offset); - for (i = 0; i < count; i++) - { - SEEK_STREAM (stream, offset + (*rule)[i].offset); - (*rule)[i].BacktrackGlyphCount - = read_glyph_ids (stream, &(*rule)[i].Backtrack, 0); - if (! (*rule)[i].BacktrackGlyphCount) - return 0; - (*rule)[i].InputGlyphCount - = read_glyph_ids (stream, &(*rule)[i].Input, -1); - if (! (*rule)[i].InputGlyphCount) - return 0; - (*rule)[i].LookaheadGlyphCount - = read_glyph_ids (stream, &(*rule)[i].LookAhead, 0); - if (! (*rule)[i].LookaheadGlyphCount) - return 0; - (*rule)[i].SubstCount - = read_subst_lookup_record (stream, &(*rule)[i].SubstLookupRecord); - if (! (*rule)[i].SubstCount) - return 0; - } - return count; -} - - -static unsigned -read_chain_subrule_set (OTF_Stream *stream, long offset, - OTF_ChainSubRuleSet **set) -{ - char *errfmt = "ChainSubRuleSet%s"; - unsigned errret = 0; - unsigned count; - int i; - - READ_UINT16 (stream, count); - if (! count) - OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - OTF_MALLOC (*set, count, ""); - for (i = 0; i < count; i++) - READ_OFFSET (stream, (*set)[i].offset); - for (i = 0; i < count; i++) - { - SEEK_STREAM (stream, offset + (*set)[i].offset); - (*set)[i].ChainSubRuleCount - = read_chain_subrule (stream, offset + (*set)[i].offset, - &(*set)[i].ChainSubRule); - if (! (*set)[i].ChainSubRuleCount) - return 0; - } - return count; -} - -static unsigned -read_chain_subclass_rule (OTF_Stream *stream, long offset, - OTF_ChainSubClassRule **rule) -{ - char *errfmt = "ChainSubClassRule%s"; - unsigned errret = 0; - unsigned count; - int i; - - READ_UINT16 (stream, count); - if (! count) - OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - OTF_MALLOC (*rule, count, ""); - for (i = 0; i < count; i++) - READ_OFFSET (stream, (*rule)[i].offset); - for (i = 0; i < count; i++) - { - SEEK_STREAM (stream, offset + (*rule)[i].offset); - (*rule)[i].BacktrackGlyphCount - = read_glyph_ids (stream, (OTF_GlyphID **) &(*rule)[i].Backtrack, 0); - if (! (*rule)[i].BacktrackGlyphCount) - return 0; - (*rule)[i].InputGlyphCount - = read_glyph_ids (stream, (OTF_GlyphID **) &(*rule)[i].Input, -1); - if (! (*rule)[i].InputGlyphCount) - return 0; - (*rule)[i].LookaheadGlyphCount - = read_glyph_ids (stream, (OTF_GlyphID **) &(*rule)[i].LookAhead, 0); - if (! (*rule)[i].LookaheadGlyphCount) - return 0; - (*rule)[i].SubstCount - = read_subst_lookup_record (stream, &(*rule)[i].SubstLookupRecord); - if (! (*rule)[i].SubstCount) - return 0; - } - return count; -} - -static unsigned -read_chain_subclass_set (OTF_Stream *stream, long offset, - OTF_ChainSubClassSet **set) -{ - char *errfmt = "ChainSubClassSet%s"; - unsigned errret = 0; - unsigned count; - int i; - - READ_UINT16 (stream, count); - if (! count) - OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - OTF_MALLOC (*set, count, ""); - for (i = 0; i < count; i++) - READ_OFFSET (stream, (*set)[i].offset); - for (i = 0; i < count; i++) - { - SEEK_STREAM (stream, offset + (*set)[i].offset); - (*set)[i].ChainSubClassRuleCnt - = read_chain_subclass_rule (stream, offset + (*set)[i].offset, - &(*set)[i].ChainSubClassRule); - if (! (*set)[i].ChainSubClassRuleCnt) - return 0; - } - return count; -} - - -static int -read_lookup_subtable_gsub (OTF_Stream *stream, long offset, - unsigned type, OTF_LookupSubTable *subtable) -{ - char *errfmt = "GSUB LookupSubTable%s"; - int errret = -1; - int count; - - SEEK_STREAM (stream, offset); - READ_UINT16 (stream, subtable->Format); - switch (type) - { - case 1: - if (subtable->Format == 1) - { - if (read_coverage (stream, offset, &subtable->Coverage) < 0) - return -1; - READ_INT16 (stream, subtable->sub.gsub.single1.DeltaGlyphID); - } - else if (subtable->Format == 2) - { - if (read_coverage (stream, offset, &subtable->Coverage) < 0) - return -1; - subtable->sub.gsub.single2.GlyphCount - = read_glyph_ids (stream, &subtable->sub.gsub.single2.Substitute, - 0); - if (! subtable->sub.gsub.single2.GlyphCount) - return -1; - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); - break; - - case 2: - if (subtable->Format == 1) - { - read_coverage (stream, offset, &subtable->Coverage); - subtable->sub.gsub.multiple1.SequenceCount - = read_sequence (stream, offset, - &subtable->sub.gsub.multiple1.Sequence); - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); - break; - - case 3: - break; - - case 4: - if (subtable->Format == 1) - { - read_coverage (stream, offset, &subtable->Coverage); - count = (read_ligature_set - (stream, offset, - &subtable->sub.gsub.ligature1.LigatureSet)); - if (count < 0) - return -1; - subtable->sub.gsub.ligature1.LigSetCount = (unsigned) count; - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); - break; - - case 6: - if (subtable->Format == 1) - { - read_coverage (stream, offset, &subtable->Coverage); - subtable->sub.gsub.chain_context1.ChainSubRuleSetCount - = (read_chain_subrule_set - (stream, offset, - &subtable->sub.gsub.chain_context1.ChainSubRuleSet)); - } - else if (subtable->Format == 2) - { - read_coverage (stream, offset, &subtable->Coverage); - read_class_def (stream, offset, - &subtable->sub.gsub.chain_context2.Backtrack); - read_class_def (stream, offset, - &subtable->sub.gsub.chain_context2.Input); - read_class_def (stream, offset, - &subtable->sub.gsub.chain_context2.LookAhead); - subtable->sub.gsub.chain_context2.ChainSubClassSetCnt - = (read_chain_subclass_set - (stream, offset, - &subtable->sub.gsub.chain_context2.ChainSubClassSet)); - } - else if (subtable->Format == 3) - { - count = (read_coverage_list - (stream, offset, - &subtable->sub.gsub.chain_context3.Backtrack)); - if (count < 0) - return -1; - subtable->sub.gsub.chain_context3.BacktrackGlyphCount - = (unsigned) count; - count = (read_coverage_list - (stream, offset, - &subtable->sub.gsub.chain_context3.Input)); - if (count <= 0) - return -1; - subtable->sub.gsub.chain_context3.InputGlyphCount - = (unsigned) count; - subtable->Coverage = subtable->sub.gsub.chain_context3.Input[0]; - count = (read_coverage_list - (stream, offset, - &subtable->sub.gsub.chain_context3.LookAhead)); - subtable->sub.gsub.chain_context3.LookaheadGlyphCount - = (unsigned) count; - subtable->sub.gsub.chain_context3.SubstCount - = (read_subst_lookup_record - (stream, &subtable->sub.gsub.chain_context3.SubstLookupRecord)); - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); - break; - - - default: - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)"); - } - return 0; -} - - -/* GPOS */ - -static int -read_value_record (OTF_Stream *stream, long offset, - enum OTF_ValueFormat bit, OTF_ValueRecord *value_record) -{ - int errret = -1; - OTF_StreamState state; - int size, i; - - if (! bit) - return 0; - for (i = 0, size = 0; i < 8; i++) - if (bit & (1 << i)) - size += 2; - - if (bit & OTF_XPlacement) - READ_INT16 (stream, value_record->XPlacement); - if (bit & OTF_XPlacement) - READ_INT16 (stream, value_record->YPlacement); - if (bit & OTF_XAdvance) - READ_INT16 (stream, value_record->XAdvance); - if (bit & OTF_YAdvance) - READ_INT16 (stream, value_record->YAdvance); - if (bit & OTF_XPlaDevice) - READ_OFFSET (stream, value_record->XPlaDevice.offset); - if (bit & OTF_YPlaDevice) - READ_OFFSET (stream, value_record->YPlaDevice.offset); - if (bit & OTF_XAdvDevice) - READ_OFFSET (stream, value_record->XAdvDevice.offset); - if (bit & OTF_YAdvDevice) - READ_OFFSET (stream, value_record->YAdvDevice.offset); - SAVE_STREAM (stream, state); - if (value_record->XPlaDevice.offset) - { - if (read_device_table (stream, offset, &value_record->XPlaDevice) < 0) - return -1; - } - if (value_record->YPlaDevice.offset) - { - if (read_device_table (stream, offset, &value_record->YPlaDevice) < 0) - return -1; - } - if (value_record->XAdvDevice.offset) - { - if (read_device_table (stream, offset, &value_record->XAdvDevice) < 0) - return -1; - } - if (value_record->YAdvDevice.offset) - { - if (read_device_table (stream, offset, &value_record->YAdvDevice) < 0) - return -1; - } - RESTORE_STREAM (stream, state); - return 0; -} - - -static int -read_anchor (OTF_Stream *stream, long offset, OTF_Anchor *anchor) -{ - char *errfmt = "Anchor%s"; - int errret = -1; - - SEEK_STREAM (stream, offset + anchor->offset); - READ_UINT16 (stream, anchor->AnchorFormat); - READ_INT16 (stream, anchor->XCoordinate); - READ_INT16 (stream, anchor->YCoordinate); - if (anchor->AnchorFormat == 1) - ; - else if (anchor->AnchorFormat == 2) - { - READ_UINT16 (stream, anchor->f.f1.AnchorPoint); - } - else if (anchor->AnchorFormat == 3) - { - READ_OFFSET (stream, anchor->f.f2.XDeviceTable.offset); - READ_OFFSET (stream, anchor->f.f2.YDeviceTable.offset); - if (anchor->f.f2.XDeviceTable.offset) - { - if (read_device_table (stream, offset + anchor->offset, - &anchor->f.f2.XDeviceTable) < 0) - return -1; - } - if (anchor->f.f2.YDeviceTable.offset) - { - if (read_device_table (stream, offset + anchor->offset, - &anchor->f.f2.YDeviceTable) < 0) - return -1; - } - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (invalid format)"); - - return 0; -} - -static int -read_mark_array (OTF_Stream *stream, long offset, OTF_MarkArray *array) -{ - char *errfmt = "MarkArray%s"; - int errret = -1; - OTF_StreamState state; - int i; - - READ_OFFSET (stream, array->offset); - SAVE_STREAM (stream, state); - SEEK_STREAM (stream, offset + array->offset); - READ_UINT16 (stream, array->MarkCount); - OTF_MALLOC (array->MarkRecord, array->MarkCount, ""); - for (i = 0; i < array->MarkCount; i++) - { - READ_UINT16 (stream, array->MarkRecord[i].Class); - READ_OFFSET (stream, array->MarkRecord[i].MarkAnchor.offset); - } - for (i = 0; i < array->MarkCount; i++) - if (read_anchor (stream, offset + array->offset, - &array->MarkRecord[i].MarkAnchor) < 0) - return -1;; - RESTORE_STREAM (stream, state); - return 0; -} - -static int -read_base_array (OTF_Stream *stream, long offset, - unsigned ClassCount, OTF_BaseArray *array) -{ - char *errfmt = "BaseArray%s"; - int errret = -1; - OTF_StreamState state; - int i, j; - - READ_OFFSET (stream, array->offset); - SAVE_STREAM (stream, state); - SEEK_STREAM (stream, offset + array->offset); - READ_UINT16 (stream, array->BaseCount); - OTF_MALLOC (array->BaseRecord, array->BaseCount, ""); - for (i = 0; i < array->BaseCount; i++) - { - OTF_MALLOC (array->BaseRecord[i].BaseAnchor, ClassCount, - " (BaseRecord)"); - for (j = 0; j < ClassCount; j++) - READ_OFFSET (stream, array->BaseRecord[i].BaseAnchor[j].offset); - } - for (i = 0; i < array->BaseCount; i++) - for (j = 0; j < ClassCount; j++) - if (read_anchor (stream, offset + array->offset, - &array->BaseRecord[i].BaseAnchor[j]) < 0) - return -1; - RESTORE_STREAM (stream, state); - return 0; -} - - -static OTF_Class1Record * -read_class1_record_list (OTF_Stream *stream, long offset, - unsigned num1, enum OTF_ValueFormat bit1, - unsigned num2, enum OTF_ValueFormat bit2) -{ - char *errfmt = "Class1Record%s"; - void *errret = NULL; - OTF_Class1Record *rec; - int i, j; - - OTF_MALLOC (rec, num1, ""); - for (i = 0; i < num1; i++) - { - OTF_CALLOC (rec[i].Class2Record, num2, " (Class2Record)"); - for (j = 0; j < num2; j++) - { - if (read_value_record (stream, offset, - bit1, &rec[i].Class2Record[j].Value1) < 0 - || read_value_record (stream, offset, - bit2, &rec[i].Class2Record[j].Value2) < 0) - return NULL; - } - } - return rec; -} - - -static int -read_lookup_subtable_gpos (OTF_Stream *stream, long offset, unsigned type, - OTF_LookupSubTable *subtable) -{ - char *errfmt = "GPOS LookupSubTable%s"; - int errret = -1; - - SEEK_STREAM (stream, offset); - READ_UINT16 (stream, subtable->Format); - switch (type) - { - case 1: -#if 0 - if (subtable->Format == 1) - { - read_coverage (stream, offset, &subtable->Coverage); - subtable->sub.gsub.single1.DeltaGlyphID = READ_INT16 (stream); - } - else if (subtable->Format == 2) - { - read_coverage (stream, offset, &subtable->Coverage); - subtable->sub.gsub.single2.GlyphCount - = read_glyph_ids (stream, - &subtable->sub.gsub.single2.Substitute, 0); - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); -#endif - break; - - case 2: - if (subtable->Format == 1) - { - read_coverage (stream, offset, &subtable->Coverage); - } - else if (subtable->Format == 2) - { - SEEK_STREAM (stream, offset + 2); - read_coverage (stream, offset, &subtable->Coverage); - READ_UINT16 (stream, subtable->sub.gpos.pair2.ValueFormat1); - READ_UINT16 (stream, subtable->sub.gpos.pair2.ValueFormat2); - read_class_def (stream, offset, &subtable->sub.gpos.pair2.ClassDef1); - read_class_def (stream, offset, &subtable->sub.gpos.pair2.ClassDef2); - READ_UINT16 (stream, subtable->sub.gpos.pair2.Class1Count); - READ_UINT16 (stream, subtable->sub.gpos.pair2.Class2Count); - subtable->sub.gpos.pair2.Class1Record - = read_class1_record_list (stream, offset, - subtable->sub.gpos.pair2.Class1Count, - subtable->sub.gpos.pair2.ValueFormat1, - subtable->sub.gpos.pair2.Class2Count, - subtable->sub.gpos.pair2.ValueFormat2); - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); - break; - - case 4: - if (subtable->Format == 1) - { - read_coverage (stream, offset, &subtable->Coverage); - read_coverage (stream, offset, - &subtable->sub.gpos.mark_base1.BaseCoverage); - READ_UINT16 (stream, subtable->sub.gpos.mark_base1.ClassCount); - read_mark_array (stream, offset, - &subtable->sub.gpos.mark_base1.MarkArray); - read_base_array (stream, offset, - subtable->sub.gpos.mark_base1.ClassCount, - &subtable->sub.gpos.mark_base1.BaseArray); - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); - break; - - case 6: -#if 0 - if (subtable->Format == 1) - { - read_coverage (stream, offset, - &subtable->sub.gsub.chain_context1.Coverage); - subtable->sub.gsub.chain_context1.ChainSubRuleSetCount - = (read_chain_subrule_set - (stream, offset, - &subtable->sub.gsub.chain_context1.ChainSubRuleSet)); - } - else if (subtable->Format == 2) - { - read_coverage (stream, offset, - &subtable->sub.gsub.chain_context2.Coverage); - read_class_def (stream, offset, - &subtable->sub.gsub.chain_context2.Backtrack); - read_class_def (stream, offset, - &subtable->sub.gsub.chain_context2.Input); - read_class_def (stream, offset, - &subtable->sub.gsub.chain_context2.LookAhead); - subtable->sub.gsub.chain_context2.ChainSubClassSetCnt - = (read_chain_subclass_set - (stream, offset, - &subtable->sub.gsub.chain_context2.ChainSubClassSet)); - } - else if (subtable->Format == 3) - { - subtable->sub.gsub.chain_context3.BacktrackGlyphCount - = (read_coverage_list - (stream, offset, - &subtable->sub.gsub.chain_context3.Backtrack)); - subtable->sub.gsub.chain_context3.InputGlyphCount - = (read_coverage_list - (stream, offset, - &subtable->sub.gsub.chain_context3.Input)); - subtable->sub.gsub.chain_context3.LookaheadGlyphCount - = (read_coverage_list - (stream, offset, - &subtable->sub.gsub.chain_context3.LookAhead)); - subtable->sub.gsub.chain_context3.SubstCount - = (read_subst_lookup_record - (stream, &subtable->sub.gsub.chain_context3.SubstLookupRecord)); - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); -#endif - - default: - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)"); - } - return 0; -} - - -static void * -read_gpos_table (OTF_Stream *stream) -{ - char *errfmt = "GPOS%s"; - void *errret = NULL; - OTF_GPOS *gpos; - - OTF_CALLOC (gpos, 1, ""); - READ_FIXED (stream, gpos->Version); - READ_OFFSET (stream, gpos->ScriptList.offset); - READ_OFFSET (stream, gpos->FeatureList.offset); - READ_OFFSET (stream, gpos->LookupList.offset); - - if (read_script_list (stream, gpos->ScriptList.offset, - &gpos->ScriptList) < 0 - || read_feature_list (stream, gpos->FeatureList.offset, - &gpos->FeatureList) < 0 - || read_lookup_list (stream, gpos->LookupList.offset, - &gpos->LookupList, 0) < 0) - return NULL; - return gpos; -} - - -#if 0 -/* BASE */ - -static OTF_BASE * -read_base_table (OTF_Stream *stream, long offset) -{ - OTF_BASE *base; - - OTF_MALLOC (base, 1); - - return base; -} - - -/* JSTF */ - -static OTF_JSTF * -read_jstf_table (OTF_Stream *stream, long offset) -{ - OTF_JSTF *jstf; - - OTF_MALLOC (jstf, 1); - - return jstf; -} -#endif - -/* GDEF */ -static int -read_attach_list (OTF_Stream *stream, long offset, OTF_AttachList *list) -{ - char *errfmt = "AttachList%s"; - int errret = -1; - int i, j; - - if (read_coverage (stream, offset, &list->Coverage) < 0) - return -1; - READ_UINT16 (stream, list->GlyphCount); - OTF_MALLOC (list->AttachPoint, list->GlyphCount, ""); - for (i = 0; i < list->GlyphCount; i++) - READ_OFFSET (stream, list->AttachPoint[i].offset); - for (i = 0; i < list->GlyphCount; i++) - { - int count; - - SEEK_STREAM (stream, offset + list->AttachPoint[i].offset); - READ_UINT16 (stream, count); - list->AttachPoint[i].PointCount = count; - OTF_MALLOC (list->AttachPoint[i].PointIndex, count, " (PointIndex)"); - for (j = 0; j < count; j++) - READ_UINT16 (stream, list->AttachPoint[i].PointIndex[j]); - } - return 0; -} - -static void -free_attach_list (OTF_AttachList *list) -{ -} - -static int -read_caret_value (OTF_Stream *stream, long offset, OTF_CaretValue *caret) -{ - char *errfmt = "CaretValue%s"; - int errret = -1; - - SEEK_STREAM (stream, offset + caret->offset); - READ_UINT16 (stream, caret->CaretValueFormat); - if (caret->CaretValueFormat == 1) - READ_INT16 (stream, caret->f.f1.Coordinate); - else if (caret->CaretValueFormat == 2) - READ_UINT16 (stream, caret->f.f2.CaretValuePoint); - else if (caret->CaretValueFormat == 3) - { - READ_INT16 (stream, caret->f.f3.Coordinate); - if (read_device_table (stream, offset + caret->offset, - &caret->f.f3.DeviceTable) < 0) - return -1; - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); - return 0; -} - -static int -read_lig_caret_list (OTF_Stream *stream, long offset, OTF_LigCaretList *list) -{ - char *errfmt = "LigCaretList%s"; - int errret = -1; - int i, j; - - if (read_coverage (stream, offset, &list->Coverage) < 0) - return -1; - READ_UINT16 (stream, list->LigGlyphCount); - OTF_MALLOC (list->LigGlyph, list->LigGlyphCount, ""); - for (i = 0; i < list->LigGlyphCount; i++) - READ_OFFSET (stream, list->LigGlyph[i].offset); - for (i = 0; i < list->LigGlyphCount; i++) - { - int count; - - SEEK_STREAM (stream, offset + list->LigGlyph[i].offset); - READ_UINT16 (stream, count); - list->LigGlyph[i].CaretCount = count; - OTF_MALLOC (list->LigGlyph[i].CaretValue, count, " (CaretValue)"); - for (j = 0; j < count; j++) - READ_OFFSET (stream, list->LigGlyph[i].CaretValue[j].offset); - for (j = 0; j < count; j++) - if (read_caret_value (stream, offset + list->LigGlyph[i].offset, - &list->LigGlyph[i].CaretValue[j]) < 0) - return -1; - } - return 0; -} - -static void -free_lig_caret_list (OTF_LigCaretList *list) -{ -} - -static int -read_gdef_header (OTF_Stream *stream, OTF_GDEFHeader *header) -{ - int errret = -1; - - READ_FIXED (stream, header->Version); - READ_OFFSET (stream, header->GlyphClassDef); - READ_OFFSET (stream, header->AttachList); - READ_OFFSET (stream, header->LigCaretList); - READ_OFFSET (stream, header->MarkAttachClassDef); - return 0; -} - -static void * -read_gdef_table (OTF_Stream *stream) -{ - char *errfmt = "GDEF%s"; - void *errret = NULL; - OTF_GDEF *gdef; - - OTF_CALLOC (gdef, 1, ""); - read_gdef_header (stream, (OTF_GDEFHeader *) &gdef->header); - if (gdef->header.GlyphClassDef) - { - gdef->glyph_class_def.offset = gdef->header.GlyphClassDef; - read_class_def_without_offset (stream, &gdef->glyph_class_def); - } - if (gdef->header.AttachList) - read_attach_list (stream, gdef->header.AttachList, - &gdef->attach_list); - if (gdef->header.LigCaretList) - read_lig_caret_list (stream, gdef->header.LigCaretList, - &gdef->lig_caret_list); - if (gdef->header.MarkAttachClassDef) - { - gdef->mark_attach_class_def.offset = gdef->header.MarkAttachClassDef; - read_class_def_without_offset (stream, &gdef->mark_attach_class_def); - } - - return gdef; -} - -static void -free_gdef_table (OTF_GDEF *gdef) -{ - if (gdef->header.GlyphClassDef) - free_class_def (&gdef->glyph_class_def); - if (gdef->header.AttachList) - free_attach_list (&gdef->attach_list); - if (gdef->header.LigCaretList) - free_lig_caret_list (&gdef->lig_caret_list); - if (gdef->header.MarkAttachClassDef) - free_class_def (&gdef->mark_attach_class_def); - free (gdef); -} - - - - -/* cmap */ - -static void * -read_cmap_table (OTF_Stream *stream) -{ - char *errfmt = "cmap%s"; - void *errret = NULL; - OTF_cmap *cmap; - int i; - - OTF_CALLOC (cmap, 1, ""); - READ_USHORT (stream, cmap->version); - READ_USHORT (stream, cmap->numTables); - OTF_MALLOC (cmap->EncodingRecord, cmap->numTables, ""); - for (i = 0; i < cmap->numTables; i++) - { - READ_USHORT (stream, cmap->EncodingRecord[i].platformID); - READ_USHORT (stream, cmap->EncodingRecord[i].encodingID); - READ_ULONG (stream, cmap->EncodingRecord[i].offset); - if (cmap->EncodingRecord[i].platformID == 3 - && cmap->EncodingRecord[i].encodingID == 1) - cmap->Unicode = cmap->EncodingRecord + i; - } - for (i = 0; i < cmap->numTables; i++) - { - unsigned format; - - SEEK_STREAM (stream, cmap->EncodingRecord[i].offset); - READ_USHORT (stream, format); - cmap->EncodingRecord[i].subtable.format = format; - READ_USHORT (stream, cmap->EncodingRecord[i].subtable.length); - if (format == 8 || format == 10 || format == 12) - { - READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length); - READ_ULONG (stream, cmap->EncodingRecord[i].subtable.language); - } - else - { - READ_USHORT (stream, cmap->EncodingRecord[i].subtable.language); - } - switch (format) - { - case 0: - { - OTF_MALLOC (cmap->EncodingRecord[i].subtable.f.f0, 1, - " (EncodingRecord)"); - READ_BYTES (stream, - cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray, - 256); - } - break; - - case 2: - break; - - case 4: - { - OTF_EncodingSubtable4 *sub4; - int segCount; - int j; - unsigned dummy; - - OTF_MALLOC (sub4, 1, " (EncodingSubtable4)"); - cmap->EncodingRecord[i].subtable.f.f4 = sub4; - READ_USHORT (stream, sub4->segCountX2); - segCount = sub4->segCountX2 / 2; - READ_USHORT (stream, sub4->searchRange); - READ_USHORT (stream, sub4->entrySelector); - READ_USHORT (stream, sub4->rangeShift); - OTF_MALLOC (sub4->segments, segCount, " (segCount)"); - for (j = 0; j < segCount; j++) - READ_USHORT (stream, sub4->segments[j].endCount); - READ_USHORT (stream, dummy); - for (j = 0; j < segCount; j++) - READ_USHORT (stream, sub4->segments[j].startCount); - for (j = 0; j < segCount; j++) - READ_SHORT (stream, sub4->segments[j].idDelta); - for (j = 0; j < segCount; j++) - { - unsigned off; - unsigned rest = 2 * (segCount - j); - - READ_USHORT (stream, off); - if (off == 0) - sub4->segments[j].idRangeOffset = 0xFFFF; - else - sub4->segments[j].idRangeOffset = (off - rest) / 2; - } - j = (cmap->EncodingRecord[i].subtable.length - - (14 + 2 * (segCount * 4 + 1))); - sub4->GlyphCount = j / 2; - OTF_MALLOC (sub4->glyphIdArray, sub4->GlyphCount, " (GlyphCount)"); - for (j = 0; j < sub4->GlyphCount; j++) - READ_USHORT (stream, sub4->glyphIdArray[j]); - } - } - } - return cmap; -} - -static void -free_cmap_table (OTF_cmap *cmap) -{ - int i; - - for (i = 0; i < cmap->numTables; i++) - { - unsigned format = cmap->EncodingRecord[i].subtable.format; - - switch (format) - { - case 0: - free (cmap->EncodingRecord[i].subtable.f.f0); - break; - - case 4: - { - OTF_EncodingSubtable4 *sub4 - = cmap->EncodingRecord[i].subtable.f.f4; - - free (sub4->glyphIdArray); - free (sub4->segments); - free (sub4); - } - break; - } - } - free (cmap); -} - - - -/* TABLE: name */ - -static char * -read_name (OTF_Stream *stream, OTF_NameRecord *rec, int bytes) -{ - char *errfmt = "nameID (%d)"; - void *errret = NULL; - OTF_StreamState state; - char *str; - int i; - int c; - - SAVE_STREAM (stream, state); - SEEK_STREAM (stream, stream->pos + rec->offset); - - if (bytes == 1) - { - OTF_MALLOC (str, rec->length + 1, (void *) rec->nameID); - READ_BYTES (stream, str, rec->length); - for (i = 0; i < rec->length; i++) - if (str[i] < 0) - str[i] = '?'; - } - else if (bytes == 2) - { - OTF_MALLOC (str, rec->length / 2 + 1, (void *) rec->nameID); - for (i = 0; i < rec->length / 2; i++) - { - READ_USHORT (stream, c); - if (c >= 128) - c = '?'; - str[i] = c; - } - } - else if (bytes == 4) - { - OTF_MALLOC (str, rec->length / 4 + 1, (void *) rec->nameID); - for (i = 0; i < rec->length / 4; i++) - { - READ_ULONG (stream, c); - if (c >= 128) - c = '?'; - str[i] = c; - } - } - str[i] = '\0'; - RESTORE_STREAM (stream, state); - return str; -} - -static void * -read_name_table (OTF_Stream *stream) -{ - char *errfmt = "name%s"; - void *errret = NULL; - OTF_name *name; - int i; - - OTF_CALLOC (name, 1, ""); - READ_USHORT (stream, name->format); - READ_USHORT (stream, name->count); - READ_USHORT (stream, name->stringOffset); - OTF_MALLOC (name->nameRecord, name->count, ""); - for (i = 0; i < name->count; i++) - { - OTF_NameRecord *rec = name->nameRecord + i; - - READ_USHORT (stream, rec->platformID); - READ_USHORT (stream, rec->encodingID); - READ_USHORT (stream, rec->languageID); - READ_USHORT (stream, rec->nameID); - READ_USHORT (stream, rec->length); - READ_USHORT (stream, rec->offset); - } - for (i = 0; i < name->count; i++) - { - OTF_NameRecord *rec = name->nameRecord + i; - int nameID = rec->nameID; - - if (nameID <= OTF_max_nameID - && ! name->name[nameID]) - { - if (rec->platformID == 0) - name->name[nameID] = read_name (stream, rec, - rec->encodingID <= 3 ? 2 : 4); - else if (rec->platformID == 1 - && rec->encodingID == 0) - name->name[nameID] = read_name (stream, rec, 1); - else if (rec->platformID == 3 - && (rec->encodingID == 1 || rec->encodingID == 10)) - name->name[nameID] = read_name (stream, - rec, rec->encodingID == 1 ? 2 : 4); - } - } - - return name; -} - -static void -free_name_table (OTF_name *name) -{ - int i; - - for (i = 0; i < name->count; i++) - if (name->name[i]) - free (name->name[i]); - - free (name->nameRecord); - free (name); -} - - - -/* APIs */ - -OTF * -otf_open (char *otf_name) -{ - FILE *fp; - char *errfmt = "OTF%s"; - void *errret = NULL; - OTF_Stream *stream; - OTF *otf; - OTF_Tag head_tag, name_tag, cmap_tag, gdef_tag, gsub_tag, gpos_tag; - int i; - - fp = fopen (otf_name, "r"); - if (! fp) - OTF_ERROR (OTF_ERROR_FILE, otf_name); - - head_tag = otf_tag ("head"); - name_tag = otf_tag ("name"); - cmap_tag = otf_tag ("cmap"); - gdef_tag = otf_tag ("GDEF"); - gsub_tag = otf_tag ("GSUB"); - gpos_tag = otf_tag ("GPOS"); - - stream = make_stream (); - if (! stream) - return NULL; - - OTF_CALLOC_GOTO (otf, 1, " (body)", err); - otf->filename = strdup (otf_name); - if (! otf->filename) - { - otf_error = OTF_ERROR_MEMORY; - goto err; - } - /* Size of Offset Table is 12 bytes. */ - if (setup_stream (stream, fp, 0, 12, "Offset Table") < 0) - goto err; - if (read_offset_table (stream, &otf->offset_table) < 0) - goto err; - - /* Size of each Table Directory is 16 bytes. */ - if (setup_stream (stream, fp, 12, 16 * otf->offset_table.numTables, - "Table Directory") < 0) - goto err; - OTF_CALLOC_GOTO (otf->table_dirs, otf->offset_table.numTables, - " (OffsetTable)", err); - for (i = 0; i < otf->offset_table.numTables; i++) - { - OTF_Tag tag = read_table_directory (stream, otf->table_dirs + i); - - if (! tag) - goto err; - if (tag == head_tag) - otf->head = otf->table_dirs + i; - else if (tag == name_tag) - otf->name = otf->table_dirs + i; - else if (tag == cmap_tag) - otf->cmap = otf->table_dirs + i; - else if (tag == gdef_tag) - otf->gdef = otf->table_dirs + i; - else if (tag == gsub_tag) - otf->gsub = otf->table_dirs + i; - else if (tag == gpos_tag) - otf->gpos = otf->table_dirs + i; - else - tag = 0; - - if (tag) - { - otf->table_dirs[i].stream = make_stream (); - if (setup_stream (otf->table_dirs[i].stream, fp, - otf->table_dirs[i].offset, - otf->table_dirs[i].length, - otf->table_dirs[i].name) < 0) - goto err; - } - } - - free_stream (stream); - fclose (fp); - return otf; - - err: - free_stream (stream); - fclose (fp); - otf_close (otf); - return NULL; -} - - -void -otf_close (OTF *otf) -{ - if (otf->filename) - free (otf->filename); - if (otf->table_dirs) - free (otf->table_dirs); - if (otf->head) - free_head_table ((OTF_head *) otf->head->table); - if (otf->name) - free_name_table ((OTF_name *) otf->name->table); - if (otf->cmap) - free_cmap_table ((OTF_cmap *) otf->cmap->table); - if (otf->gdef) - free_gdef_table ((OTF_GDEF *) otf->gdef->table); -} - - -void * -otf_get_table (OTF *otf, OTF_Tag tag) -{ - char *errfmt = "OTF Table Read"; - void *errret = NULL; - OTF_TableDirectory *tabledir = NULL; - void *(*reader) (OTF_Stream *stream); - - if (tag == otf_tag ("head")) - tabledir = otf->head, reader = read_head_table; - else if (tag == otf_tag ("name")) - tabledir = otf->name, reader = read_name_table; - else if (tag == otf_tag ("cmap")) - tabledir = otf->cmap, reader = read_cmap_table; - else if (tag == otf_tag ("GDEF")) - tabledir = otf->gdef, reader = read_gdef_table; - else if (tag == otf_tag ("GSUB")) - tabledir = otf->gsub, reader = read_gsub_table; - else if (tag == otf_tag ("GPOS")) - tabledir = otf->gpos, reader = read_gpos_table; - else - OTF_ERROR (OTF_ERROR_TABLE, " (unsupported)"); - - if (! tabledir) - OTF_ERROR (OTF_ERROR_TABLE, " (not found)"); - if (! tabledir->stream) - OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)"); - if (! tabledir->table) - { - tabledir->table = (*reader) (tabledir->stream); - if (! tabledir->table) - { - free_stream (tabledir->stream); - tabledir->stream = NULL; - OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)"); - } - } - return tabledir->table; -} diff --git a/src/otf-proc.c b/src/otf-proc.c deleted file mode 100644 index 8c5a87d..0000000 --- a/src/otf-proc.c +++ /dev/null @@ -1,584 +0,0 @@ -#include -#include -#include - -#include "otf.h" -#include "otf-util.h" - -#define GSTRING_DELETE(gstring, from, len) \ - do { \ - memmove (gstring->glyphs + from, gstring->glyphs + from + len, \ - sizeof (OTF_Glyph) * (gstring->used - from - len)); \ - gstring->used -= len; \ - } while (0) - - -#define GSTRING_INSERT(gstring, pos, len) \ - do { \ - if (gstring->used + len > gstring->size) \ - { \ - char *errfmt = "GSTRING%s"; \ - \ - gstring->size = gstring->used + len; \ - OTF_REALLOC (gstring->glyphs, gstring->size, NULL); \ - } \ - memmove (gstring->glyphs + pos + len, gstring->glyphs + pos, \ - sizeof (OTF_Glyph) * (gstring->used - pos)); \ - gstring->used += len; \ - } while (0) - - -static int -gstring_subst (OTF_GlyphString *gstring, int from, int to, - OTF_GlyphID *ids, int num) -{ - int errret = -1; - int len = to - from; - int i; - - if (len < num) - GSTRING_INSERT (gstring, from, (num - len)); - else if (len > num) - GSTRING_DELETE (gstring, from, (len - num)); - for (i = 0; i < num; i++) - gstring->glyphs[from + i].glyph_id = ids[i]; - return 0; -} - - -static int -get_coverage_index (OTF_Coverage *coverage, OTF_GlyphID id) -{ - int i; - - if (coverage->CoverageFormat == 1) - { - for (i = 0; i < coverage->Count; i++) - if (coverage->table.GlyphArray[i] == id) - return i; - } - else - { - for (i = 0; i < coverage->Count; i++) - if (coverage->table.RangeRecord[i].Start <= id - && coverage->table.RangeRecord[i].End >= id) - return (coverage->table.RangeRecord[i].StartCoverageIndex - + (id - coverage->table.RangeRecord[i].Start)); - } - return -1; -} - -static OTF_LangSys * -get_langsys (OTF_ScriptList *script_list, - OTF_Tag script_tag, OTF_Tag langsys_tag) -{ - int i, j; - - for (i = 0; i < script_list->ScriptCount; i++) - if (script_list->Script[i].ScriptTag == script_tag) - { - OTF_Script *script = script_list->Script + i; - - if (! langsys_tag) - return &script->DefaultLangSys; - for (j = 0; j < script->LangSysCount; j++) - if (script->LangSysRecord[j].LangSysTag == langsys_tag) - return script->LangSys + j; - return &script->DefaultLangSys; - } - - return NULL; -} - -static unsigned -get_class_def (OTF_ClassDef *class_def, OTF_GlyphID glyph_id) -{ - if (class_def->ClassFormat == 1) - { - int idx = (int) glyph_id - (int) class_def->f.f1.StartGlyph; - - if (idx >= 0 && idx < class_def->f.f1.GlyphCount) - return class_def->f.f1.ClassValueArray[idx]; - } - else - { - int i; - - for (i = 0; i < class_def->f.f2.ClassRangeCount; i++) - if (glyph_id >= class_def->f.f2.ClassRangeRecord[i].Start - && glyph_id >= class_def->f.f2.ClassRangeRecord[i].End) - return class_def->f.f2.ClassRangeRecord[i].Class; - } - return 0; -} - - -static int -lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, - OTF_GlyphString *gstring, int gidx) -{ - char *errfmt = "GSUB Looking up%s"; - int errret = -1; - OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index; - unsigned int flag = lookup->LookupFlag; - int orig_gidx = gidx; - OTF_Glyph *g = gstring->glyphs + gidx; - int i; - - if (! g->glyph_id - || (g->GlyphClass - && (flag & (1 << g->GlyphClass)))) - { - // printf ("type %d at %d skiped\n", lookup->LookupType, gidx); - return (gidx + 1); - } - - //printf ("@%d idx:%d type:%d...", - //gidx, lookup_list_index, lookup->LookupType); - - /* Try all subtables until one of them handles the current glyph. */ - for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++) - { - OTF_LookupSubTable *subtable = lookup->SubTable + i; - int coverage_idx; - - // printf ("subtype:%d ", subtable->Format); - if (subtable->Coverage.offset) - { - coverage_idx = get_coverage_index (&subtable->Coverage, - g->glyph_id); - if (coverage_idx < 0) - { - // printf ("not covererd "); - continue; - } - } - - switch (lookup->LookupType) - { - case 1: - if (subtable->Format == 1) - g->glyph_id += subtable->sub.gsub.single1.DeltaGlyphID; - else - g->glyph_id = subtable->sub.gsub.single2.Substitute[coverage_idx]; - gidx++; - break; - - case 2: - { - OTF_GSUB_Multiple1 *multiple1 = &subtable->sub.gsub.multiple1; - OTF_Sequence *seq = multiple1->Sequence + coverage_idx; - - gstring_subst (gstring, gidx, gidx + 1, - seq->Substitute, seq->GlyphCount); - gidx += seq->GlyphCount; - } - break; - - case 3: - OTF_ERROR (OTF_ERROR_GSUB_PROC, " (LookupType not yet supported)"); - - case 4: - if (subtable->Format == 1) - { - OTF_GSUB_Ligature1 *lig1 = &subtable->sub.gsub.ligature1; - OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx; - int j; - - for (j = 0; j < ligset->LigatureCount; j++) - { - OTF_Ligature *lig = ligset->Ligature + j; - int k; - - if (gstring->used - gidx < lig->CompCount) - continue; - for (k = 1; k < lig->CompCount; k++) - if (gstring->glyphs[gidx + k].glyph_id - != lig->Component[k - 1]) - break; - if (k < lig->CompCount) - continue; - gstring_subst (gstring, gidx, gidx + lig->CompCount, - &lig->LigGlyph, 1); - gidx++; - break; - } - } - else - OTF_ERROR (OTF_ERROR_GSUB_PROC, " (invalid SubFormat)"); - break; - - case 6: - if (subtable->Format == 1) - OTF_ERROR (OTF_ERROR_GSUB_PROC, " (not yet supported)"); - else if (subtable->Format == 2) - OTF_ERROR (OTF_ERROR_GSUB_PROC, " (not yet supported)"); - else - { - OTF_GSUB_ChainContext3 *context3 - = &subtable->sub.gsub.chain_context3; - int back_gidx = gidx - context3->BacktrackGlyphCount; - int fore_gidx = gidx + context3->InputGlyphCount; - int orig_used; - int j; - - if (back_gidx < 0 - || fore_gidx + context3->LookaheadGlyphCount > gstring->used) - break; - - for (j = 0; j < context3->BacktrackGlyphCount; j++) - if (get_coverage_index (context3->Backtrack + j, - gstring->glyphs[back_gidx + j].glyph_id) - < 0) - break; - /* Start from the secoding coverage_idx because the - first one is the same as subtable->Coverage and thus - already tested */ - for (j = 1; j < context3->InputGlyphCount; j++) - if (get_coverage_index (context3->Input + j - 1, - gstring->glyphs[gidx + j].glyph_id) - < 0) - break; - for (j = 0; j < context3->LookaheadGlyphCount; j++) - if (get_coverage_index (context3->LookAhead + j, - gstring->glyphs[fore_gidx + j].glyph_id) - < 0) - break; - - orig_used = gstring->used; - for (j = 0; j < context3->SubstCount; j++) - lookup_gsub (lookup_list, - context3->SubstLookupRecord[j].LookupListIndex, - gstring, - gidx + context3->SubstLookupRecord[j].SequenceIndex); - gidx += context3->InputGlyphCount + (gstring->used - orig_used); - } - break; - - default: - continue; - } - } - if (gidx == orig_gidx) - { - //printf ("not applied\n"); - gidx++; - } - else - { - // printf ("done\n"); - } - return gidx; -} - -int -otf_drive_gsub (OTF *otf, OTF_Tag script_tag, OTF_Tag langsys_tag, - OTF_GlyphString *gstring) -{ - OTF_GSUB *gsub = (OTF_GSUB *) otf->gsub->table; - OTF_LangSys *langsys; - int i, j; - - if (! gsub) - gsub = (OTF_GSUB *) otf_get_table (otf, otf_tag ("GSUB")); - if (! gsub) - return -1; - langsys = get_langsys (&gsub->ScriptList, script_tag, langsys_tag); - if (! langsys) - return -1; - - for (i = 0; i < langsys->FeatureCount; i++) - { - OTF_Feature *feature - = gsub->FeatureList.Feature + langsys->FeatureIndex[i]; - - for (j = 0; j < feature->LookupCount; j++) - { - int gidx = 0; - - while (gidx < gstring->used) - gidx = lookup_gsub (&gsub->LookupList, feature->LookupListIndex[j], - gstring, gidx); - } - } - - return 0; -} - - - -/* GPOS */ -unsigned -get_anchor (OTF_Anchor *anchor, OTF_ValueRecord *rec) -{ - unsigned value_format = OTF_XPlacement | OTF_YPlacement; - - rec->XPlacement = anchor->XCoordinate; - rec->YPlacement = anchor->YCoordinate; - if (anchor->AnchorFormat == 1) - /* Nothing to do */ - ; - else if (anchor->AnchorFormat == 2) - /* Not yet implemented */ - ; - else if (anchor->AnchorFormat == 3) - /* Not yet implemented */ - ; - return value_format; -} - - -static int -lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, - OTF_GlyphString *gstring, int gidx) -{ - char *errfmt = "GPOS Looking up%s"; - int errret = -1; - OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index; - unsigned int flag = lookup->LookupFlag; - int orig_gidx = gidx; - OTF_Glyph *g = gstring->glyphs + gidx; - int i; - - if (! g->glyph_id - || (g->GlyphClass - && (flag & (1 << g->GlyphClass)))) - { - // printf ("type %d at %d skiped\n", lookup->LookupType, gidx); - return (gidx + 1); - } - - // printf ("0x%04X@%d idx:%d type:%d...", - // g->glyph_id, gidx, lookup_list_index, lookup->LookupType); - - /* Try all subtables until one of them handles the current glyph. */ - for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++) - { - OTF_LookupSubTable *subtable = lookup->SubTable + i; - int coverage_idx; - - // printf ("subtype:%d ", subtable->Format); - if (subtable->Coverage.offset) - { - coverage_idx = get_coverage_index (&subtable->Coverage, - g->glyph_id); - if (coverage_idx < 0) - { - // printf ("not covererd "); - continue; - } - } - - switch (lookup->LookupType) - { - case 1: - OTF_ERROR (OTF_ERROR_GPOS_PROC, " (not yet supported)"); - - case 2: - if (gidx + 1 >= gstring->used) - continue; - if (subtable->Format == 1) - OTF_ERROR (OTF_ERROR_GPOS_PROC, " (not yet supported)"); - else if (subtable->Format == 2) - { - OTF_GPOS_Pair2 *pair2 = &subtable->sub.gpos.pair2; - unsigned class1, class2; - - printf ("GPOS 2-2: c:0x%x g:0x%x\n", g->c, g->glyph_id); - gidx++; - class1 = get_class_def (&pair2->ClassDef1, g->glyph_id); - class2 = get_class_def (&pair2->ClassDef2, g[1].glyph_id); - g->positioning_type = lookup->LookupType; - g->f.f2.format = pair2->ValueFormat1; - g->f.f2.value - = &pair2->Class1Record[class1].Class2Record[class2].Value1; - if (pair2->ValueFormat2) - { - g++, gidx++; - g->positioning_type = lookup->LookupType; - g->f.f2.format = pair2->ValueFormat2; - g->f.f2.value - = &pair2->Class1Record[class1].Class2Record[class2].Value2; - } - } - break; - - case 3: - OTF_ERROR (OTF_ERROR_GPOS_PROC, " (not yet supported)"); - - case 4: - if (gidx < 1) - continue; - if (subtable->Format == 1) - { - OTF_GPOS_MarkBase1 *mark_base1 = &subtable->sub.gpos.mark_base1; - OTF_MarkRecord *mark_record; - OTF_BaseRecord *base_record; - OTF_Anchor *anchor1, *anchor2; - int coverage_idx_base - = get_coverage_index (&mark_base1->BaseCoverage, - g[-1].glyph_id); - - if (coverage_idx_base < 0) - continue; - printf ("GPOS 4-1: c:0x%x g:0x%x\n", g->c, g->glyph_id); - mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx; - base_record - = mark_base1->BaseArray.BaseRecord + coverage_idx_base; - anchor1 = &mark_record->MarkAnchor; - anchor2 = &base_record->BaseAnchor[mark_record->Class]; - g->positioning_type = lookup->LookupType; - g->f.f4.mark_anchor = anchor1; - g->f.f4.base_anchor = anchor2; - break; - } - else - OTF_ERROR (OTF_ERROR_GPOS_PROC, " (not yet supported)"); - break; - - case 6: - OTF_ERROR (OTF_ERROR_GPOS_PROC, " (not yet supported)"); - break; - - default: - continue; - } - } - if (gidx == orig_gidx) - { - // printf ("not applied\n"); - gidx++; - } - else - { - // printf ("done\n"); - } - return gidx; -} - -int -otf_drive_gpos (OTF *otf, OTF_Tag script_tag, OTF_Tag langsys_tag, - OTF_GlyphString *gstring) -{ - OTF_GPOS *gpos = (OTF_GPOS *) otf->gpos->table; - OTF_LangSys *langsys; - int i, j; - - if (! gpos) - gpos = (OTF_GPOS *) otf_get_table (otf, otf_tag ("GPOS")); - if (! gpos) - return -1; - langsys = get_langsys (&gpos->ScriptList, script_tag, langsys_tag); - if (! langsys) - return -1; - - for (i = 0; i < langsys->FeatureCount; i++) - { - OTF_Feature *feature - = gpos->FeatureList.Feature + langsys->FeatureIndex[i]; - - for (j = 0; j < feature->LookupCount; j++) - { - int gidx = 0; - - while (gidx < gstring->used) - gidx = lookup_gpos (&gpos->LookupList, feature->LookupListIndex[j], - gstring, gidx); - } - } - - return 0; -} - - - -int -otf_drive_gdef (OTF *otf, OTF_GlyphString *gstring) -{ - int i; - OTF_GDEF *gdef = (OTF_GDEF *) otf->gdef->table; - - if (! gdef) - gdef = (OTF_GDEF *) otf_get_table (otf, otf_tag ("GDEF")); - if (! gdef) - return -1; - - if (gdef->glyph_class_def.offset) - for (i = 0; i < gstring->used; i++) - gstring->glyphs[i].GlyphClass - = get_class_def (&gdef->glyph_class_def, - gstring->glyphs[i].glyph_id); - - if (gdef->mark_attach_class_def.offset) - for (i = 0; i < gstring->used; i++) - gstring->glyphs[i].MarkAttachClass - = get_class_def (&gdef->mark_attach_class_def, - gstring->glyphs[i].glyph_id); - - return 0; -} - -int -lookup_cmap (OTF_cmap *cmap, int c) -{ - int i; - - if (! cmap || ! cmap->Unicode) - return 0; - - switch (cmap->Unicode->subtable.format) - { - case 0: - break; - - case 4: - { - OTF_EncodingSubtable4 *sub4 = cmap->Unicode->subtable.f.f4; - int segCount = sub4->segCountX2 / 2; - - for (i = 0; i < segCount; i++) - if (c <= sub4->segments[i].endCount) - break; - if (i == segCount || c < sub4->segments[i].startCount) - return 0; - if (sub4->segments[i].idRangeOffset == 0xFFFF) - return c + sub4->segments[i].idDelta; - return sub4->glyphIdArray[sub4->segments[i].idRangeOffset - + (c - sub4->segments[i].startCount)]; - } - break; - } - return 0; -} - -int -otf_drive_cmap (OTF *otf, OTF_GlyphString *gstring) -{ - OTF_cmap *cmap = (OTF_cmap *) otf->cmap->table; - int i; - - if (! cmap) - cmap = (OTF_cmap *) otf_get_table (otf, otf_tag ("cmap")); - if (! cmap) - return -1; - - for (i = 0; i < gstring->used; i++) - gstring->glyphs[i].glyph_id = lookup_cmap (cmap, gstring->glyphs[i].c); - - return 0; -} - -int -otf_drive_table (OTF *otf, OTF_Tag script, OTF_Tag langsys, - OTF_GlyphString *gstring) -{ - if (otf_drive_cmap (otf, gstring) < 0) - return -1; - if (otf_drive_gdef (otf, gstring) < 0) - return -1; - if (otf_drive_gsub (otf, script, langsys, gstring) < 0) - return -1; - if (otf_drive_gpos (otf, script, langsys, gstring) < 0) - return -1; - return 0; -} diff --git a/src/otf-util.c b/src/otf-util.c deleted file mode 100644 index 8a39323..0000000 --- a/src/otf-util.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include - -#include "otf.h" - -static char *error_message; -int otf_error; - -static char *error_string[] = - { - "Memory shortage", - "File error", - "Invalid OTF table contents" - }; - -int -otf__error (int err, char *fmt, void *arg) -{ - if (! error_message) - error_message = (char *) malloc (256); - sprintf (error_message, "OTF-Error (%s): ", error_string[-err - 1]); - sprintf (error_message + strlen (error_message), fmt, arg); - otf_error = err; - return 0; -} - -void -otf_perror (char *prefix) -{ - if (otf_error < 0) - { - if (prefix) - fprintf (stderr, "%s: %s", prefix, error_message); - else - fprintf (stderr, "%s", error_message); - } -} - - -OTF_Tag -otf_tag (char *str) -{ - unsigned char *p = (unsigned char *) str; - - if (! str) - return (OTF_Tag) 0; - return (OTF_Tag) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); -} - diff --git a/src/otf-util.h b/src/otf-util.h deleted file mode 100644 index 28af06f..0000000 --- a/src/otf-util.h +++ /dev/null @@ -1,40 +0,0 @@ -#define OTF_ERROR(err, arg) \ - return (otf__error ((err), errfmt, (arg)), errret) - -/* Memory allocation macros. */ - -#define OTF_MALLOC(p, size, arg) \ - do { \ - ((p) = (void *) malloc (sizeof (*(p)) * (size))); \ - if (! (p)) \ - OTF_ERROR (OTF_ERROR_MEMORY, arg); \ - } while (0) - - -#define OTF_CALLOC(p, size, arg) \ - do { \ - (p) = (void *) calloc (size, sizeof (*(p))); \ - if (! (p)) \ - OTF_ERROR (OTF_ERROR_MEMORY, arg); \ - } while (0) - - -#define OTF_REALLOC(p, size, arg) \ - do { \ - (p) = (void *) realloc ((p), sizeof (*(p)) * (size)); \ - if (! (p)) \ - OTF_ERROR (OTF_ERROR_MEMORY, arg); \ - } while (0) - -#define OTF_CALLOC_GOTO(p, size, arg, label) \ - do { \ - (p) = (void *) calloc (size, sizeof (*(p))); \ - if (! (p)) \ - { \ - otf__error (OTF_ERROR_MEMORY, errfmt, (arg)); \ - goto label; \ - } \ - } while (0) - -extern int otf__error (int err, char *fmt, void *arg); - diff --git a/src/otf.h b/src/otf.h index 8d82894..6f5aa14 100644 --- a/src/otf.h +++ b/src/otf.h @@ -74,14 +74,14 @@ extern void otf_perror (char *prefix); #define OTF_ERROR_TABLE -3 /*** - @brief CMAP processing error. + @brief CMAP driving error. When the OTF library an invalid data in an OTF table, the variable otf_error is set to this value. */ -#define OTF_ERROR_CMAP_PROC -4 -#define OTF_ERROR_GDEF_PROC -5 -#define OTF_ERROR_GSUB_PROC -6 -#define OTF_ERROR_GPOS_PROC -7 +#define OTF_ERROR_CMAP_DRIVE -4 +#define OTF_ERROR_GDEF_DRIVE -5 +#define OTF_ERROR_GSUB_DRIVE -6 +#define OTF_ERROR_GPOS_DRIVE -7 /*** @} */ @@ -978,25 +978,16 @@ typedef struct typedef struct { - FILE *fp; - char *name; - long pos; - long bufsize; - long allocated; - unsigned char *buf; -} OTF_Stream; - -typedef struct -{ OTF_Tag tag; char name[5]; unsigned checkSum; unsigned offset; unsigned length; void *table; - OTF_Stream *stream; } OTF_TableDirectory; +typedef struct OTF_InternalData OTF_InternalData; + typedef struct { char *filename; @@ -1011,13 +1002,14 @@ typedef struct /* The following tables are not yet supported. */ // OTF_TableDirectory *base; // OTF_TableDirectory *jstf; + OTF_InternalData *internal_data; } OTF; typedef struct { /* Character code of the glyph. This is the only member that a client has to set before calling the OTF library function - otf_proc. */ + otfdrive. */ int c; /* Glyph ID of the glyph. */ diff --git a/src/otfdrive.c b/src/otfdrive.c new file mode 100644 index 0000000..75e930d --- /dev/null +++ b/src/otfdrive.c @@ -0,0 +1,587 @@ +#include +#include +#include + +#include "otf.h" +#include "otfutil.h" + +#define GSTRING_DELETE(gstring, from, len) \ + do { \ + memmove (gstring->glyphs + from, gstring->glyphs + from + len, \ + sizeof (OTF_Glyph) * (gstring->used - from - len)); \ + gstring->used -= len; \ + } while (0) + + +#define GSTRING_INSERT(gstring, pos, len) \ + do { \ + if (gstring->used + len > gstring->size) \ + { \ + char *errfmt = "GSTRING%s"; \ + \ + gstring->size = gstring->used + len; \ + gstring->glyphs = (OTF_Glyph *) realloc (gstring->glyphs, \ + gstring->size); \ + if (! gstring->glyphs) \ + OTF_ERROR (OTF_ERROR_MEMORY, ""); \ + } \ + memmove (gstring->glyphs + pos + len, gstring->glyphs + pos, \ + sizeof (OTF_Glyph) * (gstring->used - pos)); \ + gstring->used += len; \ + } while (0) + + +static int +gstring_subst (OTF_GlyphString *gstring, int from, int to, + OTF_GlyphID *ids, int num) +{ + int errret = -1; + int len = to - from; + int i; + + if (len < num) + GSTRING_INSERT (gstring, from, (num - len)); + else if (len > num) + GSTRING_DELETE (gstring, from, (len - num)); + for (i = 0; i < num; i++) + gstring->glyphs[from + i].glyph_id = ids[i]; + return 0; +} + + +static int +get_coverage_index (OTF_Coverage *coverage, OTF_GlyphID id) +{ + int i; + + if (coverage->CoverageFormat == 1) + { + for (i = 0; i < coverage->Count; i++) + if (coverage->table.GlyphArray[i] == id) + return i; + } + else + { + for (i = 0; i < coverage->Count; i++) + if (coverage->table.RangeRecord[i].Start <= id + && coverage->table.RangeRecord[i].End >= id) + return (coverage->table.RangeRecord[i].StartCoverageIndex + + (id - coverage->table.RangeRecord[i].Start)); + } + return -1; +} + +static OTF_LangSys * +get_langsys (OTF_ScriptList *script_list, + OTF_Tag script_tag, OTF_Tag langsys_tag) +{ + int i, j; + + for (i = 0; i < script_list->ScriptCount; i++) + if (script_list->Script[i].ScriptTag == script_tag) + { + OTF_Script *script = script_list->Script + i; + + if (! langsys_tag) + return &script->DefaultLangSys; + for (j = 0; j < script->LangSysCount; j++) + if (script->LangSysRecord[j].LangSysTag == langsys_tag) + return script->LangSys + j; + return &script->DefaultLangSys; + } + + return NULL; +} + +static unsigned +get_class_def (OTF_ClassDef *class_def, OTF_GlyphID glyph_id) +{ + if (class_def->ClassFormat == 1) + { + int idx = (int) glyph_id - (int) class_def->f.f1.StartGlyph; + + if (idx >= 0 && idx < class_def->f.f1.GlyphCount) + return class_def->f.f1.ClassValueArray[idx]; + } + else + { + int i; + + for (i = 0; i < class_def->f.f2.ClassRangeCount; i++) + if (glyph_id >= class_def->f.f2.ClassRangeRecord[i].Start + && glyph_id >= class_def->f.f2.ClassRangeRecord[i].End) + return class_def->f.f2.ClassRangeRecord[i].Class; + } + return 0; +} + + +static int +lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, + OTF_GlyphString *gstring, int gidx) +{ + char *errfmt = "GSUB Looking up%s"; + int errret = -1; + OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index; + unsigned int flag = lookup->LookupFlag; + int orig_gidx = gidx; + OTF_Glyph *g = gstring->glyphs + gidx; + int i; + + if (! g->glyph_id + || (g->GlyphClass + && (flag & (1 << g->GlyphClass)))) + { + // printf ("type %d at %d skiped\n", lookup->LookupType, gidx); + return (gidx + 1); + } + + //printf ("@%d idx:%d type:%d...", + //gidx, lookup_list_index, lookup->LookupType); + + /* Try all subtables until one of them handles the current glyph. */ + for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++) + { + OTF_LookupSubTable *subtable = lookup->SubTable + i; + int coverage_idx; + + // printf ("subtype:%d ", subtable->Format); + if (subtable->Coverage.offset) + { + coverage_idx = get_coverage_index (&subtable->Coverage, + g->glyph_id); + if (coverage_idx < 0) + { + // printf ("not covererd "); + continue; + } + } + + switch (lookup->LookupType) + { + case 1: + if (subtable->Format == 1) + g->glyph_id += subtable->sub.gsub.single1.DeltaGlyphID; + else + g->glyph_id = subtable->sub.gsub.single2.Substitute[coverage_idx]; + gidx++; + break; + + case 2: + { + OTF_GSUB_Multiple1 *multiple1 = &subtable->sub.gsub.multiple1; + OTF_Sequence *seq = multiple1->Sequence + coverage_idx; + + gstring_subst (gstring, gidx, gidx + 1, + seq->Substitute, seq->GlyphCount); + gidx += seq->GlyphCount; + } + break; + + case 3: + OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (LookupType not yet supported)"); + + case 4: + if (subtable->Format == 1) + { + OTF_GSUB_Ligature1 *lig1 = &subtable->sub.gsub.ligature1; + OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx; + int j; + + for (j = 0; j < ligset->LigatureCount; j++) + { + OTF_Ligature *lig = ligset->Ligature + j; + int k; + + if (gstring->used - gidx < lig->CompCount) + continue; + for (k = 1; k < lig->CompCount; k++) + if (gstring->glyphs[gidx + k].glyph_id + != lig->Component[k - 1]) + break; + if (k < lig->CompCount) + continue; + gstring_subst (gstring, gidx, gidx + lig->CompCount, + &lig->LigGlyph, 1); + gidx++; + break; + } + } + else + OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)"); + break; + + case 6: + if (subtable->Format == 1) + OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)"); + else if (subtable->Format == 2) + OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)"); + else + { + OTF_GSUB_ChainContext3 *context3 + = &subtable->sub.gsub.chain_context3; + int back_gidx = gidx - context3->BacktrackGlyphCount; + int fore_gidx = gidx + context3->InputGlyphCount; + int orig_used; + int j; + + if (back_gidx < 0 + || fore_gidx + context3->LookaheadGlyphCount > gstring->used) + break; + + for (j = 0; j < context3->BacktrackGlyphCount; j++) + if (get_coverage_index (context3->Backtrack + j, + gstring->glyphs[back_gidx + j].glyph_id) + < 0) + break; + /* Start from the secoding coverage_idx because the + first one is the same as subtable->Coverage and thus + already tested */ + for (j = 1; j < context3->InputGlyphCount; j++) + if (get_coverage_index (context3->Input + j - 1, + gstring->glyphs[gidx + j].glyph_id) + < 0) + break; + for (j = 0; j < context3->LookaheadGlyphCount; j++) + if (get_coverage_index (context3->LookAhead + j, + gstring->glyphs[fore_gidx + j].glyph_id) + < 0) + break; + + orig_used = gstring->used; + for (j = 0; j < context3->SubstCount; j++) + lookup_gsub (lookup_list, + context3->SubstLookupRecord[j].LookupListIndex, + gstring, + gidx + context3->SubstLookupRecord[j].SequenceIndex); + gidx += context3->InputGlyphCount + (gstring->used - orig_used); + } + break; + + default: + continue; + } + } + if (gidx == orig_gidx) + { + //printf ("not applied\n"); + gidx++; + } + else + { + // printf ("done\n"); + } + return gidx; +} + +int +otf_drive_gsub (OTF *otf, OTF_Tag script_tag, OTF_Tag langsys_tag, + OTF_GlyphString *gstring) +{ + OTF_GSUB *gsub = (OTF_GSUB *) otf->gsub->table; + OTF_LangSys *langsys; + int i, j; + + if (! gsub) + gsub = (OTF_GSUB *) otf_get_table (otf, otf_tag ("GSUB")); + if (! gsub) + return -1; + langsys = get_langsys (&gsub->ScriptList, script_tag, langsys_tag); + if (! langsys) + return -1; + + for (i = 0; i < langsys->FeatureCount; i++) + { + OTF_Feature *feature + = gsub->FeatureList.Feature + langsys->FeatureIndex[i]; + + for (j = 0; j < feature->LookupCount; j++) + { + int gidx = 0; + + while (gidx < gstring->used) + gidx = lookup_gsub (&gsub->LookupList, feature->LookupListIndex[j], + gstring, gidx); + } + } + + return 0; +} + + + +/* GPOS */ +unsigned +get_anchor (OTF_Anchor *anchor, OTF_ValueRecord *rec) +{ + unsigned value_format = OTF_XPlacement | OTF_YPlacement; + + rec->XPlacement = anchor->XCoordinate; + rec->YPlacement = anchor->YCoordinate; + if (anchor->AnchorFormat == 1) + /* Nothing to do */ + ; + else if (anchor->AnchorFormat == 2) + /* Not yet implemented */ + ; + else if (anchor->AnchorFormat == 3) + /* Not yet implemented */ + ; + return value_format; +} + + +static int +lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, + OTF_GlyphString *gstring, int gidx) +{ + char *errfmt = "GPOS Looking up%s"; + int errret = -1; + OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index; + unsigned int flag = lookup->LookupFlag; + int orig_gidx = gidx; + OTF_Glyph *g = gstring->glyphs + gidx; + int i; + + if (! g->glyph_id + || (g->GlyphClass + && (flag & (1 << g->GlyphClass)))) + { + // printf ("type %d at %d skiped\n", lookup->LookupType, gidx); + return (gidx + 1); + } + + // printf ("0x%04X@%d idx:%d type:%d...", + // g->glyph_id, gidx, lookup_list_index, lookup->LookupType); + + /* Try all subtables until one of them handles the current glyph. */ + for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++) + { + OTF_LookupSubTable *subtable = lookup->SubTable + i; + int coverage_idx; + + // printf ("subtype:%d ", subtable->Format); + if (subtable->Coverage.offset) + { + coverage_idx = get_coverage_index (&subtable->Coverage, + g->glyph_id); + if (coverage_idx < 0) + { + // printf ("not covererd "); + continue; + } + } + + switch (lookup->LookupType) + { + case 1: + OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + + case 2: + if (gidx + 1 >= gstring->used) + continue; + if (subtable->Format == 1) + OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + else if (subtable->Format == 2) + { + OTF_GPOS_Pair2 *pair2 = &subtable->sub.gpos.pair2; + unsigned class1, class2; + + printf ("GPOS 2-2: c:0x%x g:0x%x\n", g->c, g->glyph_id); + gidx++; + class1 = get_class_def (&pair2->ClassDef1, g->glyph_id); + class2 = get_class_def (&pair2->ClassDef2, g[1].glyph_id); + g->positioning_type = lookup->LookupType; + g->f.f2.format = pair2->ValueFormat1; + g->f.f2.value + = &pair2->Class1Record[class1].Class2Record[class2].Value1; + if (pair2->ValueFormat2) + { + g++, gidx++; + g->positioning_type = lookup->LookupType; + g->f.f2.format = pair2->ValueFormat2; + g->f.f2.value + = &pair2->Class1Record[class1].Class2Record[class2].Value2; + } + } + break; + + case 3: + OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + + case 4: + if (gidx < 1) + continue; + if (subtable->Format == 1) + { + OTF_GPOS_MarkBase1 *mark_base1 = &subtable->sub.gpos.mark_base1; + OTF_MarkRecord *mark_record; + OTF_BaseRecord *base_record; + OTF_Anchor *anchor1, *anchor2; + int coverage_idx_base + = get_coverage_index (&mark_base1->BaseCoverage, + g[-1].glyph_id); + + if (coverage_idx_base < 0) + continue; + printf ("GPOS 4-1: c:0x%x g:0x%x\n", g->c, g->glyph_id); + mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx; + base_record + = mark_base1->BaseArray.BaseRecord + coverage_idx_base; + anchor1 = &mark_record->MarkAnchor; + anchor2 = &base_record->BaseAnchor[mark_record->Class]; + g->positioning_type = lookup->LookupType; + g->f.f4.mark_anchor = anchor1; + g->f.f4.base_anchor = anchor2; + break; + } + else + OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + break; + + case 6: + OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + break; + + default: + continue; + } + } + if (gidx == orig_gidx) + { + // printf ("not applied\n"); + gidx++; + } + else + { + // printf ("done\n"); + } + return gidx; +} + +int +otf_drive_gpos (OTF *otf, OTF_Tag script_tag, OTF_Tag langsys_tag, + OTF_GlyphString *gstring) +{ + OTF_GPOS *gpos = (OTF_GPOS *) otf->gpos->table; + OTF_LangSys *langsys; + int i, j; + + if (! gpos) + gpos = (OTF_GPOS *) otf_get_table (otf, otf_tag ("GPOS")); + if (! gpos) + return -1; + langsys = get_langsys (&gpos->ScriptList, script_tag, langsys_tag); + if (! langsys) + return -1; + + for (i = 0; i < langsys->FeatureCount; i++) + { + OTF_Feature *feature + = gpos->FeatureList.Feature + langsys->FeatureIndex[i]; + + for (j = 0; j < feature->LookupCount; j++) + { + int gidx = 0; + + while (gidx < gstring->used) + gidx = lookup_gpos (&gpos->LookupList, feature->LookupListIndex[j], + gstring, gidx); + } + } + + return 0; +} + + + +int +otf_drive_gdef (OTF *otf, OTF_GlyphString *gstring) +{ + int i; + OTF_GDEF *gdef = (OTF_GDEF *) otf->gdef->table; + + if (! gdef) + gdef = (OTF_GDEF *) otf_get_table (otf, otf_tag ("GDEF")); + if (! gdef) + return -1; + + if (gdef->glyph_class_def.offset) + for (i = 0; i < gstring->used; i++) + gstring->glyphs[i].GlyphClass + = get_class_def (&gdef->glyph_class_def, + gstring->glyphs[i].glyph_id); + + if (gdef->mark_attach_class_def.offset) + for (i = 0; i < gstring->used; i++) + gstring->glyphs[i].MarkAttachClass + = get_class_def (&gdef->mark_attach_class_def, + gstring->glyphs[i].glyph_id); + + return 0; +} + +int +lookup_cmap (OTF_cmap *cmap, int c) +{ + int i; + + if (! cmap || ! cmap->Unicode) + return 0; + + switch (cmap->Unicode->subtable.format) + { + case 0: + break; + + case 4: + { + OTF_EncodingSubtable4 *sub4 = cmap->Unicode->subtable.f.f4; + int segCount = sub4->segCountX2 / 2; + + for (i = 0; i < segCount; i++) + if (c <= sub4->segments[i].endCount) + break; + if (i == segCount || c < sub4->segments[i].startCount) + return 0; + if (sub4->segments[i].idRangeOffset == 0xFFFF) + return c + sub4->segments[i].idDelta; + return sub4->glyphIdArray[sub4->segments[i].idRangeOffset + + (c - sub4->segments[i].startCount)]; + } + break; + } + return 0; +} + +int +otf_drive_cmap (OTF *otf, OTF_GlyphString *gstring) +{ + OTF_cmap *cmap = (OTF_cmap *) otf->cmap->table; + int i; + + if (! cmap) + cmap = (OTF_cmap *) otf_get_table (otf, otf_tag ("cmap")); + if (! cmap) + return -1; + + for (i = 0; i < gstring->used; i++) + gstring->glyphs[i].glyph_id = lookup_cmap (cmap, gstring->glyphs[i].c); + + return 0; +} + +int +otf_drive_table (OTF *otf, OTF_Tag script, OTF_Tag langsys, + OTF_GlyphString *gstring) +{ + if (otf_drive_cmap (otf, gstring) < 0) + return -1; + if (otf_drive_gdef (otf, gstring) < 0) + return -1; + if (otf_drive_gsub (otf, script, langsys, gstring) < 0) + return -1; + if (otf_drive_gpos (otf, script, langsys, gstring) < 0) + return -1; + return 0; +} diff --git a/src/otfopen.c b/src/otfopen.c new file mode 100644 index 0000000..04de9ed --- /dev/null +++ b/src/otfopen.c @@ -0,0 +1,1940 @@ +#include +#include +#include + +#include "otf.h" +#include "otfutil.h" + +/* OTF_Stream + + Example of typical usage of OTF_Stream. + + { + OTF_Stream *stream; + OTF_StreamState state; + int offset, nbytes; + + OPEN_STREAM (_FILE_NAME_, stream); + if (! stream) + _ERROR_; + SETUP_STREAM (stream, fp, 0, 256, _NAME_); + offset = READ_OFFSET (stream); + nbytes = READ_ULONG (stream); + SETUP_STREAM (stream, fp, offset, nbytes, _NAME2_); + ...; + CLOSE_STREAM (stream); + } + +*/ + +typedef struct +{ + FILE *fp; + char *name; + long pos; + long bufsize; + long allocated; + unsigned char *buf; +} OTF_Stream; + +typedef long OTF_StreamState; + +OTF_Stream * +make_stream () +{ + OTF_Stream *stream; + char *errfmt = "stream creation%s"; + void *errret = NULL; + + stream = malloc (sizeof (OTF_Stream)); + if (! stream) + OTF_ERROR (OTF_ERROR_MEMORY, ""); + return stream; +} + +int +setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes, + char *name) +{ + char *errfmt = "stream setup for %s"; + int errret = -1; + + stream->name = name; + stream->pos = 0; + if (stream->allocated < nbytes) + { + unsigned char *buf = malloc (nbytes); + + if (! buf) + OTF_ERROR (OTF_ERROR_MEMORY, stream->name); + if (stream->buf) + free (stream->buf); + stream->buf = buf; + stream->allocated = nbytes; + } + stream->bufsize = nbytes; + if (fseek (fp, offset, SEEK_SET) < 0) + OTF_ERROR (OTF_ERROR_FILE, stream->name); + if (fread (stream->buf, 1, nbytes, fp) != nbytes) + OTF_ERROR (OTF_ERROR_FILE, stream->name); + return 0; +} + + +void +free_stream (OTF_Stream *stream) +{ + free (stream->buf); + free (stream); +} + +#define SAVE_STREAM(stream, state) ((state) = (stream)->pos) +#define RESTORE_STREAM(stream, state) ((stream)->pos = (state)) +#define SEEK_STREAM(stream, offset) ((stream)->pos = (offset)) + +#define STREAM_CHECK_SIZE(stream, size) \ + if ((stream)->pos + (size) > (stream)->bufsize) \ + { \ + char *errfmt = "buffer overrun in %s"; \ + \ + OTF_ERROR (OTF_ERROR_TABLE, (stream)->name); \ + return errret; \ + } \ + else + + +#define READ_USHORT(stream, var) \ + do { \ + STREAM_CHECK_SIZE ((stream), 2); \ + (var) = (((stream)->buf[(stream)->pos] << 8) \ + | (stream)->buf[(stream)->pos + 1]); \ + (stream)->pos += 2; \ + } while (0) + +#define READ_SHORT(stream, var) \ + do { \ + STREAM_CHECK_SIZE ((stream), 2); \ + (var) = (short) (((stream)->buf[(stream)->pos] << 8) \ + | (stream)->buf[(stream)->pos + 1]); \ + (stream)->pos += 2; \ + } while (0) + +#define READ_ULONG(stream, var) \ + do { \ + STREAM_CHECK_SIZE ((stream), 4); \ + (var) = (((stream)->buf[(stream)->pos] << 24) \ + | ((stream)->buf[(stream)->pos + 1] << 16) \ + | ((stream)->buf[(stream)->pos + 2] << 8) \ + | (stream)->buf[(stream)->pos + 3]); \ + (stream)->pos += 4; \ + } while (0) + +#define READ_LONG(stream, var) \ + do { \ + STREAM_CHECK_SIZE ((stream), 4); \ + (var) = (int) (((stream)->buf[(stream)->pos] << 24) \ + | ((stream)->buf[(stream)->pos + 1] << 16) \ + | ((stream)->buf[(stream)->pos + 2] << 8) \ + | (stream)->buf[(stream)->pos + 3]); \ + (stream)->pos += 4; \ + } while (0) + + +#define READ_FIXED(stream, fixed) \ + do { \ + READ_USHORT ((stream), (fixed).high); \ + READ_USHORT ((stream), (fixed).low); \ + } while (0) + + +#define READ_BYTES(stream, p, nbytes) \ + do { \ + STREAM_CHECK_SIZE ((stream), (nbytes)); \ + memcpy ((p), (stream)->buf + (stream)->pos, (nbytes)); \ + (stream)->pos += (nbytes); \ + } while (0) + + +#define READ_TAG READ_ULONG +#define READ_OFFSET READ_USHORT +#define READ_UINT16 READ_USHORT +#define READ_INT16 READ_SHORT +#define READ_GLYPHID READ_USHORT + + + +#define OTF_MEMORY_RECORD_SIZE 1024 + +struct OTF_MemoryRecord +{ + int used; + void *memory[OTF_MEMORY_RECORD_SIZE]; + struct OTF_MemoryRecord *next; +}; + +typedef struct OTF_MemoryRecord OTF_MemoryRecord; + +struct OTF_InternalData { + int head_index; + int name_index; + int cmap_index; + int gdef_index; + int gsub_index; + int gpos_index; + OTF_Stream *work_stream; + OTF_Stream **streams; + OTF_MemoryRecord *memory_record; +}; + + +static int +allocate_memory_record (OTF *otf) +{ + OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data; + OTF_MemoryRecord *mem_rec = calloc (1, sizeof (OTF_MemoryRecord)); + + if (! mem_rec) + return -1; + mem_rec->used = 0; + mem_rec->next = internal_data->memory_record; + internal_data->memory_record = mem_rec; + return 0; +} + +/* Memory allocation macros. */ + +#define OTF_MALLOC(p, size, arg) \ + do { \ + (p) = malloc (sizeof (*(p)) * (size)); \ + if (! (p) \ + || ((((OTF_InternalData *) otf->internal_data)->memory_record->used \ + >= OTF_MEMORY_RECORD_SIZE) \ + && (allocate_memory_record (otf) < 0))) \ + OTF_ERROR (OTF_ERROR_MEMORY, (arg)); \ + ((OTF_InternalData *) otf->internal_data)->memory_record->memory \ + [((OTF_InternalData *) otf->internal_data)->memory_record->used++] \ + = (p); \ + } while (0) + + +#define OTF_CALLOC(p, size, arg) \ + do { \ + (p) = calloc ((size), sizeof (*(p))); \ + if (! (p) \ + || ((((OTF_InternalData *) otf->internal_data)->memory_record->used \ + >= OTF_MEMORY_RECORD_SIZE) \ + && (allocate_memory_record (otf) < 0))) \ + OTF_ERROR (OTF_ERROR_MEMORY, (arg)); \ + ((OTF_InternalData *) otf->internal_data)->memory_record->memory \ + [((OTF_InternalData *) otf->internal_data)->memory_record->used++] \ + = (p); \ + } while (0) + + + + +int +read_offset_table (OTF *otf, OTF_Stream *stream, OTF_OffsetTable *table) +{ + int errret = -1; + + READ_FIXED (stream, table->sfnt_version); + READ_USHORT (stream, table->numTables); + READ_USHORT (stream, table->searchRange); + READ_USHORT (stream, table->enterSelector); + READ_USHORT (stream, table->rangeShift); + return 0; +} + +static OTF_Tag +read_table_directory (OTF_Stream *stream, OTF_TableDirectory *table) +{ + int errret = 0; + OTF_Tag tag; + + READ_TAG (stream, tag); + table->tag = tag; + table->name[0] = tag >> 24; + table->name[1] = (tag >> 16) & 0xFF; + table->name[0] = (tag >> 8) & 0xFF; + table->name[0] = tag >> 8; + table->name[0] = '\0'; + READ_ULONG (stream, table->checkSum); + READ_ULONG (stream, table->offset); + READ_ULONG (stream, table->length); + return tag; +} + +static int +read_otf_header (OTF *otf, FILE *fp) +{ + char *errfmt = "otf header%s"; + int errret = -1; + OTF_InternalData *internal_data; + OTF_Tag head_tag, name_tag, cmap_tag, gdef_tag, gsub_tag, gpos_tag; + OTF_Stream *stream; + int i; + + OTF_CALLOC (internal_data, 1, " (InternalData"); + otf->internal_data = internal_data; + + if (allocate_memory_record (otf) < 0) + OTF_ERROR (OTF_ERROR_MEMORY, " (InternalData)"); + + head_tag = otf_tag ("head"); + name_tag = otf_tag ("name"); + cmap_tag = otf_tag ("cmap"); + gdef_tag = otf_tag ("GDEF"); + gsub_tag = otf_tag ("GSUB"); + gpos_tag = otf_tag ("GPOS"); + + stream = make_stream (); + if (! stream) + return -1; + + internal_data->work_stream = stream; + + /* Size of Offset Table is 12 bytes. */ + if (setup_stream (stream, fp, 0, 12, "Offset Table") < 0) + return -1; + if (read_offset_table (otf, stream, &otf->offset_table) < 0) + return -1; + + /* Size of each Table Directory is 16 bytes. */ + if (setup_stream (stream, fp, 12, 16 * otf->offset_table.numTables, + "Table Directory") < 0) + return -1; + + OTF_CALLOC (otf->table_dirs, otf->offset_table.numTables, " (OffsetTable)"); + OTF_CALLOC (internal_data->streams, otf->offset_table.numTables, + " (OffsetTable)"); + for (i = 0; i < otf->offset_table.numTables; i++) + { + OTF_Tag tag = read_table_directory (stream, otf->table_dirs + i); + + if (! tag) + return -1; + if (tag == head_tag) + otf->head = otf->table_dirs + i; + else if (tag == name_tag) + otf->name = otf->table_dirs + i; + else if (tag == cmap_tag) + otf->cmap = otf->table_dirs + i; + else if (tag == gdef_tag) + otf->gdef = otf->table_dirs + i; + else if (tag == gsub_tag) + otf->gsub = otf->table_dirs + i; + else if (tag == gpos_tag) + otf->gpos = otf->table_dirs + i; + else + tag = 0; + + if (tag) + { + internal_data->streams[i] = make_stream (); + if (setup_stream (internal_data->streams[i], fp, + otf->table_dirs[i].offset, + otf->table_dirs[i].length, + otf->table_dirs[i].name) < 0) + return -1; + } + } + + internal_data->work_stream = NULL; + free_stream (stream); + return 0; +} + + + + +static void * +read_head_table (OTF *otf, OTF_Stream *stream) +{ + char *errfmt = "head%s"; + void *errret = NULL; + OTF_head *head; + + OTF_CALLOC (head, 1, ""); + READ_FIXED (stream, head->TableVersionNumber); + READ_FIXED (stream, head->fontRevision); + READ_ULONG (stream, head->checkSumAdjustment); + READ_ULONG (stream, head->magicNumber); + READ_USHORT (stream, head->flags); + READ_USHORT (stream, head->unitsPerEm); + + return head; +} + + + +static int +read_script_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_ScriptList *list) +{ + char *errfmt = "Script List%s"; + int errret = -1; + int i, j, k; + + SEEK_STREAM (stream, offset); + READ_USHORT (stream, list->ScriptCount); + OTF_CALLOC (list->Script, list->ScriptCount, ""); + + for (i = 0; i < list->ScriptCount; i++) + { + READ_TAG (stream, list->Script[i].ScriptTag); + READ_OFFSET (stream, list->Script[i].offset); + } + for (i = 0; i < list->ScriptCount; i++) + { + OTF_Script *script = list->Script + i; + long script_offset = offset + script->offset; + + SEEK_STREAM (stream, script_offset); + READ_OFFSET (stream, script->DefaultLangSysOffset); + READ_USHORT (stream, script->LangSysCount); + OTF_MALLOC (script->LangSysRecord, script->LangSysCount, " (LangSys)"); + OTF_CALLOC (script->LangSys, script->LangSysCount, " (LangSys)"); + for (j = 0; j < script->LangSysCount; j++) + { + READ_TAG (stream, script->LangSysRecord[j].LangSysTag); + READ_OFFSET (stream, script->LangSysRecord[j].LangSys); + } + + if (script->DefaultLangSysOffset) + { + OTF_LangSys *langsys = &script->DefaultLangSys; + + SEEK_STREAM (stream, script_offset + script->DefaultLangSysOffset); + READ_OFFSET (stream, langsys->LookupOrder); + READ_USHORT (stream, langsys->ReqFeatureIndex); + READ_USHORT (stream, langsys->FeatureCount); + OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount, + " (FeatureIndex)"); + for (k = 0; k < langsys->FeatureCount; k++) + READ_USHORT (stream, langsys->FeatureIndex[k]); + } + + for (j = 0; j < script->LangSysCount; j++) + { + OTF_LangSys *langsys = script->LangSys + j; + + SEEK_STREAM (stream, + script_offset + script->LangSysRecord[j].LangSys); + READ_OFFSET (stream, langsys->LookupOrder); + READ_USHORT (stream, langsys->ReqFeatureIndex); + READ_USHORT (stream, langsys->FeatureCount); + OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount, + " (FeatureIndex)"); + for (k = 0; k < langsys->FeatureCount; k++) + READ_USHORT (stream, langsys->FeatureIndex[k]); + } + } + + return 0; +} + +static int +read_feature_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_FeatureList *list) +{ + char *errfmt = "Feature List%s"; + int errret = -1; + int i, j; + + READ_UINT16 (stream, list->FeatureCount); + OTF_CALLOC (list->Feature, list->FeatureCount, ""); + for (i = 0; i < list->FeatureCount; i++) + { + READ_TAG (stream, list->Feature[i].FeatureTag); + READ_OFFSET (stream, list->Feature[i].offset); + } + for (i = 0; i < list->FeatureCount; i++) + { + OTF_Feature *feature = list->Feature + i; + + SEEK_STREAM (stream, offset + feature->offset); + READ_OFFSET (stream, feature->FeatureParams); + READ_UINT16 (stream, feature->LookupCount); + OTF_MALLOC (feature->LookupListIndex, feature->LookupCount, + " (LookupListIndex)"); + for (j = 0; j < feature->LookupCount; j++) + READ_UINT16 (stream, feature->LookupListIndex[j]); + } + + return 0; +} + +static int read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, + long offset, unsigned type, + OTF_LookupSubTable *subtable); +static int read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, + long offset, unsigned type, + OTF_LookupSubTable *subtable); + +static int +read_lookup_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_LookupList *list, int gsub) +{ + char *errfmt = "Lookup List%s"; + int errret = -1; + int i, j; + + SEEK_STREAM (stream, offset); + READ_UINT16 (stream, list->LookupCount); + OTF_CALLOC (list->Lookup, list->LookupCount, ""); + + for (i = 0; i < list->LookupCount; i++) + READ_OFFSET (stream, list->Lookup[i].offset); + for (i = 0; i < list->LookupCount; i++) + { + OTF_Lookup *lookup = list->Lookup + i; + + SEEK_STREAM (stream, offset + lookup->offset); + READ_UINT16 (stream, lookup->LookupType); + READ_UINT16 (stream, lookup->LookupFlag); + READ_UINT16 (stream, lookup->SubTableCount); + OTF_MALLOC (lookup->SubTableOffset, lookup->SubTableCount, + " (SubTableOffset)"); + OTF_CALLOC (lookup->SubTable, lookup->SubTableCount, + " (SubTable)"); + for (j = 0; j < lookup->SubTableCount; j++) + READ_OFFSET (stream, lookup->SubTableOffset[j]); + if (gsub) + for (j = 0; j < lookup->SubTableCount; j++) + { + long this_offset + = offset + lookup->offset + lookup->SubTableOffset[j]; + + if (read_lookup_subtable_gsub (otf, stream, this_offset, + lookup->LookupType, + lookup->SubTable + j) < 0) + return errret; + } + else + for (j = 0; j < lookup->SubTableCount; j++) + { + long this_offset + = offset + lookup->offset + lookup->SubTableOffset[j]; + + if (read_lookup_subtable_gpos (otf, stream, this_offset, + lookup->LookupType, + lookup->SubTable + j) < 0) + return errret; + } + } + + return 0; +} + + +static int +read_glyph_ids (OTF *otf, OTF_Stream *stream, OTF_GlyphID **ids, int minus) +{ + char *errfmt = "GlyphID List%s"; + int errret = -1; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + return 0; + OTF_MALLOC (*ids, count, ""); + for (i = 0; i < count + minus; i++) + READ_GLYPHID (stream, (*ids)[i]); + return (int) count; +} + +static unsigned +read_range_records (OTF *otf, OTF_Stream *stream, OTF_RangeRecord **record) +{ + char *errfmt = "RangeRecord%s"; + unsigned errret = 0; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + return 0; + OTF_MALLOC (*record, count, ""); + for (i = 0; i < count; i++) + { + READ_GLYPHID (stream, (*record)[i].Start); + READ_GLYPHID (stream, (*record)[i].End); + READ_UINT16 (stream, (*record)[i].StartCoverageIndex); + } + return count; +} + + +static int +read_coverage (OTF *otf, OTF_Stream *stream, long offset, + OTF_Coverage *coverage) +{ + char *errfmt = "Coverage%s"; + int errret = -1; + OTF_StreamState state; + int count; + + READ_OFFSET (stream, coverage->offset); + SAVE_STREAM (stream, state); + SEEK_STREAM (stream, offset + coverage->offset); + READ_UINT16 (stream, coverage->CoverageFormat); + if (coverage->CoverageFormat == 1) + count = read_glyph_ids (otf, stream, &coverage->table.GlyphArray, 0); + else if (coverage->CoverageFormat == 2) + count = read_range_records (otf, stream, &coverage->table.RangeRecord); + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid Format)"); + if (count < 0) + return -1; + coverage->Count = (unsigned) count; + RESTORE_STREAM (stream, state); + return 0; +} + +static int +read_coverage_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_Coverage **coverage) +{ + char *errfmt = "Coverage List%s"; + int errret = -1; + int count; + int i; + + READ_UINT16 (stream, count); + if (! count) + return 0; + OTF_MALLOC (*coverage, count, ""); + for (i = 0; i < count; i++) + if (read_coverage (otf, stream, offset, (*coverage) + i) < 0) + return -1; + return count; +} + + +static int +read_class_def_without_offset (OTF *otf, OTF_Stream *stream, + OTF_ClassDef *class) +{ + char *errfmt = "ClassDef%s"; + int errret = -1; + + SEEK_STREAM (stream, class->offset); + READ_UINT16 (stream, class->ClassFormat); + if (class->ClassFormat == 1) + { + READ_GLYPHID (stream, class->f.f1.StartGlyph); + class->f.f1.GlyphCount + = (read_glyph_ids + (otf, stream, (OTF_GlyphID **) &class->f.f1.ClassValueArray, 0)); + if (! class->f.f1.GlyphCount) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + } + else if (class->ClassFormat == 2) + { + class->f.f2.ClassRangeCount + = (read_range_records + (otf, stream, (OTF_RangeRecord **) &class->f.f2.ClassRangeRecord)); + if (! class->f.f2.ClassRangeCount) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); + return 0; +} + + +static int +read_class_def (OTF *otf, OTF_Stream *stream, long offset, OTF_ClassDef *class) +{ + char *errfmt = "ClassDef%s"; + int errret = -1; + OTF_StreamState state; + + READ_OFFSET (stream, class->offset); + SAVE_STREAM (stream, state); + SEEK_STREAM (stream, offset + class->offset); + READ_UINT16 (stream, class->ClassFormat); + if (class->ClassFormat == 1) + { + READ_GLYPHID (stream, class->f.f1.StartGlyph); + class->f.f1.GlyphCount + = (read_glyph_ids + (otf, stream, (OTF_GlyphID **) &class->f.f1.ClassValueArray, 0)); + if (! class->f.f1.GlyphCount) + return -1; + } + else if (class->ClassFormat == 2) + { + class->f.f2.ClassRangeCount + = (read_range_records + (otf, stream, (OTF_RangeRecord **) &class->f.f2.ClassRangeRecord)); + if (! class->f.f2.ClassRangeCount) + return -1; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); + + RESTORE_STREAM (stream, state); + return 0; +} + + +static int +read_device_table (OTF *otf, OTF_Stream *stream, long offset, + OTF_DeviceTable *table) +{ + char *errfmt = "Device Table%s"; + int errret = -1; + + int num, i; + unsigned val; + struct { + int int2 : 2; + int int4 : 4; + int int8 : 8; + } intval; + + SEEK_STREAM (stream, offset + table->offset); + READ_UINT16 (stream, table->StartSize); + READ_UINT16 (stream, table->EndSize); + READ_UINT16 (stream, table->DeltaFormat); + num = table->EndSize - table->StartSize + 1; + OTF_MALLOC (table->DeltaValue, num, ""); + + if (table->DeltaFormat == 1) + for (i = 0; i < num; i++) + { + if ((i % 8) == 0) + READ_UINT16 (stream, val); + intval.int2 = (val >> (14 - (i % 8) * 2)) & 0x03; + table->DeltaValue[i] = intval.int2; + } + else if (table->DeltaFormat == 2) + for (i = 0; i < num; i++) + { + if ((i % 4) == 0) + READ_UINT16 (stream, val); + intval.int4 = (val >> (12 - (i % 4) * 4)) & 0x0F; + table->DeltaValue[i] = intval.int4; + } + else if (table->DeltaFormat == 3) + for (i = 0; i < num; i++) + { + if ((i % 2) == 0) + { + READ_UINT16 (stream, val); + intval.int8 = val >> 8; + table->DeltaValue[i] = intval.int8; + } + else + { + intval.int8 = val >> 8; + table->DeltaValue[i] = intval.int8; + } + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); + return 0; +} + + +/* GSUB */ + +static void * +read_gsub_table (OTF *otf, OTF_Stream *stream) +{ + char *errfmt = "GSUB%s"; + void *errret = NULL; + OTF_GSUB *gsub; + + OTF_CALLOC (gsub, 1, ""); + READ_FIXED (stream, gsub->Version); + READ_OFFSET (stream, gsub->ScriptList.offset); + READ_OFFSET (stream, gsub->FeatureList.offset); + READ_OFFSET (stream, gsub->LookupList.offset); + + if (read_script_list (otf, stream, gsub->ScriptList.offset, + &gsub->ScriptList) < 0 + || read_feature_list (otf, stream, gsub->FeatureList.offset, + &gsub->FeatureList) < 0 + || read_lookup_list (otf, stream, gsub->LookupList.offset, + &gsub->LookupList, 1) < 0) + return NULL; + return gsub; +} + +static unsigned +read_sequence (OTF *otf, OTF_Stream *stream, long offset, OTF_Sequence **seq) +{ + char *errfmt = "Sequence%s"; + unsigned errret = 0; + unsigned count; + int i; + + READ_UINT16 (stream, count); + OTF_MALLOC (*seq, count, ""); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + for (i = 0; i < count; i++) + READ_OFFSET (stream, (*seq)[i].offset); + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*seq)[i].offset); + (*seq)[i].GlyphCount = read_glyph_ids (otf, stream, + &(*seq)[i].Substitute, 0); + if (! (*seq)[i].GlyphCount) + return 0; + } + return count; +} + +static int +read_ligature (OTF *otf, OTF_Stream *stream, long offset, + OTF_Ligature **ligature) +{ + char *errfmt = "Ligature%s"; + int errret = -1; + int count; + int i; + + READ_UINT16 (stream, count); + if (! count) + return 0; + OTF_MALLOC (*ligature, count, ""); + for (i = 0; i < count; i++) + READ_OFFSET (stream, (*ligature)[i].offset); + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*ligature)[i].offset); + READ_GLYPHID (stream, (*ligature)[i].LigGlyph); + (*ligature)[i].CompCount + = read_glyph_ids (otf, stream, &(*ligature)[i].Component, -1); + if (! (*ligature)[i].CompCount) + return -1; + } + return count; +} + +static int +read_ligature_set (OTF *otf, OTF_Stream *stream, long offset, + OTF_LigatureSet **ligset) +{ + char *errfmt = "LigatureSet%s"; + int errret = -1; + int count; + int i; + + READ_UINT16 (stream, count); + if (! count) + return 0; + OTF_MALLOC (*ligset, count, ""); + for (i = 0; i < count; i++) + READ_OFFSET (stream, (*ligset)[i].offset); + for (i = 0; i < count; i++) + { + int lig_count; + + SEEK_STREAM (stream, offset + (*ligset)[i].offset); + lig_count = read_ligature (otf, stream, offset + (*ligset)[i].offset, + &(*ligset)[i].Ligature); + if (lig_count < 0) + return -1; + (*ligset)[i].LigatureCount = (unsigned) lig_count; + } + return count; +} + +static unsigned +read_subst_lookup_record (OTF *otf, OTF_Stream *stream, + OTF_SubstLookupRecord **record) +{ + char *errfmt = "SubstLookupRecord%s"; + unsigned errret = 0; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*record, count, ""); + for (i = 0; i < count; i++) + { + READ_UINT16 (stream, (*record)[i].SequenceIndex); + READ_UINT16 (stream, (*record)[i].LookupListIndex); + } + return count; +} + +static unsigned +read_chain_subrule (OTF *otf, OTF_Stream *stream, long offset, + OTF_ChainSubRule **rule) +{ + char *errfmt = "ChainSubRule%s"; + unsigned errret = 0; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*rule, count, ""); + for (i = 0; i < count; i++) + READ_OFFSET (stream, (*rule)[i].offset); + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*rule)[i].offset); + (*rule)[i].BacktrackGlyphCount + = read_glyph_ids (otf, stream, &(*rule)[i].Backtrack, 0); + if (! (*rule)[i].BacktrackGlyphCount) + return 0; + (*rule)[i].InputGlyphCount + = read_glyph_ids (otf, stream, &(*rule)[i].Input, -1); + if (! (*rule)[i].InputGlyphCount) + return 0; + (*rule)[i].LookaheadGlyphCount + = read_glyph_ids (otf, stream, &(*rule)[i].LookAhead, 0); + if (! (*rule)[i].LookaheadGlyphCount) + return 0; + (*rule)[i].SubstCount + = read_subst_lookup_record (otf, stream, &(*rule)[i].SubstLookupRecord); + if (! (*rule)[i].SubstCount) + return 0; + } + return count; +} + + +static unsigned +read_chain_subrule_set (OTF *otf, OTF_Stream *stream, long offset, + OTF_ChainSubRuleSet **set) +{ + char *errfmt = "ChainSubRuleSet%s"; + unsigned errret = 0; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*set, count, ""); + for (i = 0; i < count; i++) + READ_OFFSET (stream, (*set)[i].offset); + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*set)[i].offset); + (*set)[i].ChainSubRuleCount + = read_chain_subrule (otf, stream, offset + (*set)[i].offset, + &(*set)[i].ChainSubRule); + if (! (*set)[i].ChainSubRuleCount) + return 0; + } + return count; +} + +static unsigned +read_chain_subclass_rule (OTF *otf, OTF_Stream *stream, long offset, + OTF_ChainSubClassRule **rule) +{ + char *errfmt = "ChainSubClassRule%s"; + unsigned errret = 0; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*rule, count, ""); + for (i = 0; i < count; i++) + READ_OFFSET (stream, (*rule)[i].offset); + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*rule)[i].offset); + (*rule)[i].BacktrackGlyphCount + = read_glyph_ids (otf, stream, + (OTF_GlyphID **) &(*rule)[i].Backtrack, 0); + if (! (*rule)[i].BacktrackGlyphCount) + return 0; + (*rule)[i].InputGlyphCount + = read_glyph_ids (otf, stream, (OTF_GlyphID **) &(*rule)[i].Input, -1); + if (! (*rule)[i].InputGlyphCount) + return 0; + (*rule)[i].LookaheadGlyphCount + = read_glyph_ids (otf, stream, (OTF_GlyphID **) &(*rule)[i].LookAhead, 0); + if (! (*rule)[i].LookaheadGlyphCount) + return 0; + (*rule)[i].SubstCount + = read_subst_lookup_record (otf, stream, &(*rule)[i].SubstLookupRecord); + if (! (*rule)[i].SubstCount) + return 0; + } + return count; +} + +static unsigned +read_chain_subclass_set (OTF *otf, OTF_Stream *stream, long offset, + OTF_ChainSubClassSet **set) +{ + char *errfmt = "ChainSubClassSet%s"; + unsigned errret = 0; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*set, count, ""); + for (i = 0; i < count; i++) + READ_OFFSET (stream, (*set)[i].offset); + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*set)[i].offset); + (*set)[i].ChainSubClassRuleCnt + = read_chain_subclass_rule (otf, stream, offset + (*set)[i].offset, + &(*set)[i].ChainSubClassRule); + if (! (*set)[i].ChainSubClassRuleCnt) + return 0; + } + return count; +} + + +static int +read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset, + unsigned type, OTF_LookupSubTable *subtable) +{ + char *errfmt = "GSUB LookupSubTable%s"; + int errret = -1; + int count; + + SEEK_STREAM (stream, offset); + READ_UINT16 (stream, subtable->Format); + switch (type) + { + case 1: + if (subtable->Format == 1) + { + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; + READ_INT16 (stream, subtable->sub.gsub.single1.DeltaGlyphID); + } + else if (subtable->Format == 2) + { + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; + subtable->sub.gsub.single2.GlyphCount + = read_glyph_ids (otf, stream, &subtable->sub.gsub.single2.Substitute, + 0); + if (! subtable->sub.gsub.single2.GlyphCount) + return -1; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 2: + if (subtable->Format == 1) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + subtable->sub.gsub.multiple1.SequenceCount + = read_sequence (otf, stream, offset, + &subtable->sub.gsub.multiple1.Sequence); + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 3: + break; + + case 4: + if (subtable->Format == 1) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + count = (read_ligature_set + (otf, stream, offset, + &subtable->sub.gsub.ligature1.LigatureSet)); + if (count < 0) + return -1; + subtable->sub.gsub.ligature1.LigSetCount = (unsigned) count; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 6: + if (subtable->Format == 1) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + subtable->sub.gsub.chain_context1.ChainSubRuleSetCount + = (read_chain_subrule_set + (otf, stream, offset, + &subtable->sub.gsub.chain_context1.ChainSubRuleSet)); + } + else if (subtable->Format == 2) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + read_class_def (otf, stream, offset, + &subtable->sub.gsub.chain_context2.Backtrack); + read_class_def (otf, stream, offset, + &subtable->sub.gsub.chain_context2.Input); + read_class_def (otf, stream, offset, + &subtable->sub.gsub.chain_context2.LookAhead); + subtable->sub.gsub.chain_context2.ChainSubClassSetCnt + = (read_chain_subclass_set + (otf, stream, offset, + &subtable->sub.gsub.chain_context2.ChainSubClassSet)); + } + else if (subtable->Format == 3) + { + count = (read_coverage_list + (otf, stream, offset, + &subtable->sub.gsub.chain_context3.Backtrack)); + if (count < 0) + return -1; + subtable->sub.gsub.chain_context3.BacktrackGlyphCount + = (unsigned) count; + count = (read_coverage_list + (otf, stream, offset, + &subtable->sub.gsub.chain_context3.Input)); + if (count <= 0) + return -1; + subtable->sub.gsub.chain_context3.InputGlyphCount + = (unsigned) count; + subtable->Coverage = subtable->sub.gsub.chain_context3.Input[0]; + count = (read_coverage_list + (otf, stream, offset, + &subtable->sub.gsub.chain_context3.LookAhead)); + subtable->sub.gsub.chain_context3.LookaheadGlyphCount + = (unsigned) count; + subtable->sub.gsub.chain_context3.SubstCount + = (read_subst_lookup_record + (otf, stream, + &subtable->sub.gsub.chain_context3.SubstLookupRecord)); + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + + default: + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)"); + } + return 0; +} + + +/* GPOS */ + +static int +read_value_record (OTF *otf, OTF_Stream *stream, long offset, + enum OTF_ValueFormat bit, OTF_ValueRecord *value_record) +{ + int errret = -1; + OTF_StreamState state; + int size, i; + + if (! bit) + return 0; + for (i = 0, size = 0; i < 8; i++) + if (bit & (1 << i)) + size += 2; + + if (bit & OTF_XPlacement) + READ_INT16 (stream, value_record->XPlacement); + if (bit & OTF_XPlacement) + READ_INT16 (stream, value_record->YPlacement); + if (bit & OTF_XAdvance) + READ_INT16 (stream, value_record->XAdvance); + if (bit & OTF_YAdvance) + READ_INT16 (stream, value_record->YAdvance); + if (bit & OTF_XPlaDevice) + READ_OFFSET (stream, value_record->XPlaDevice.offset); + if (bit & OTF_YPlaDevice) + READ_OFFSET (stream, value_record->YPlaDevice.offset); + if (bit & OTF_XAdvDevice) + READ_OFFSET (stream, value_record->XAdvDevice.offset); + if (bit & OTF_YAdvDevice) + READ_OFFSET (stream, value_record->YAdvDevice.offset); + SAVE_STREAM (stream, state); + if (value_record->XPlaDevice.offset) + { + if (read_device_table (otf, stream, offset, &value_record->XPlaDevice) < 0) + return -1; + } + if (value_record->YPlaDevice.offset) + { + if (read_device_table (otf, stream, offset, &value_record->YPlaDevice) < 0) + return -1; + } + if (value_record->XAdvDevice.offset) + { + if (read_device_table (otf, stream, offset, &value_record->XAdvDevice) < 0) + return -1; + } + if (value_record->YAdvDevice.offset) + { + if (read_device_table (otf, stream, offset, &value_record->YAdvDevice) < 0) + return -1; + } + RESTORE_STREAM (stream, state); + return 0; +} + + +static int +read_anchor (OTF *otf, OTF_Stream *stream, long offset, OTF_Anchor *anchor) +{ + char *errfmt = "Anchor%s"; + int errret = -1; + + SEEK_STREAM (stream, offset + anchor->offset); + READ_UINT16 (stream, anchor->AnchorFormat); + READ_INT16 (stream, anchor->XCoordinate); + READ_INT16 (stream, anchor->YCoordinate); + if (anchor->AnchorFormat == 1) + ; + else if (anchor->AnchorFormat == 2) + { + READ_UINT16 (stream, anchor->f.f1.AnchorPoint); + } + else if (anchor->AnchorFormat == 3) + { + READ_OFFSET (stream, anchor->f.f2.XDeviceTable.offset); + READ_OFFSET (stream, anchor->f.f2.YDeviceTable.offset); + if (anchor->f.f2.XDeviceTable.offset) + { + if (read_device_table (otf, stream, offset + anchor->offset, + &anchor->f.f2.XDeviceTable) < 0) + return -1; + } + if (anchor->f.f2.YDeviceTable.offset) + { + if (read_device_table (otf, stream, offset + anchor->offset, + &anchor->f.f2.YDeviceTable) < 0) + return -1; + } + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (invalid format)"); + + return 0; +} + +static int +read_mark_array (OTF *otf, OTF_Stream *stream, long offset, + OTF_MarkArray *array) +{ + char *errfmt = "MarkArray%s"; + int errret = -1; + OTF_StreamState state; + int i; + + READ_OFFSET (stream, array->offset); + SAVE_STREAM (stream, state); + SEEK_STREAM (stream, offset + array->offset); + READ_UINT16 (stream, array->MarkCount); + OTF_MALLOC (array->MarkRecord, array->MarkCount, ""); + for (i = 0; i < array->MarkCount; i++) + { + READ_UINT16 (stream, array->MarkRecord[i].Class); + READ_OFFSET (stream, array->MarkRecord[i].MarkAnchor.offset); + } + for (i = 0; i < array->MarkCount; i++) + if (read_anchor (otf, stream, offset + array->offset, + &array->MarkRecord[i].MarkAnchor) < 0) + return -1;; + RESTORE_STREAM (stream, state); + return 0; +} + +static int +read_base_array (OTF *otf, OTF_Stream *stream, long offset, + unsigned ClassCount, OTF_BaseArray *array) +{ + char *errfmt = "BaseArray%s"; + int errret = -1; + OTF_StreamState state; + int i, j; + + READ_OFFSET (stream, array->offset); + SAVE_STREAM (stream, state); + SEEK_STREAM (stream, offset + array->offset); + READ_UINT16 (stream, array->BaseCount); + OTF_MALLOC (array->BaseRecord, array->BaseCount, ""); + for (i = 0; i < array->BaseCount; i++) + { + OTF_MALLOC (array->BaseRecord[i].BaseAnchor, ClassCount, + " (BaseRecord)"); + for (j = 0; j < ClassCount; j++) + READ_OFFSET (stream, array->BaseRecord[i].BaseAnchor[j].offset); + } + for (i = 0; i < array->BaseCount; i++) + for (j = 0; j < ClassCount; j++) + if (read_anchor (otf, stream, offset + array->offset, + &array->BaseRecord[i].BaseAnchor[j]) < 0) + return -1; + RESTORE_STREAM (stream, state); + return 0; +} + + +static OTF_Class1Record * +read_class1_record_list (OTF *otf, OTF_Stream *stream, long offset, + unsigned num1, enum OTF_ValueFormat bit1, + unsigned num2, enum OTF_ValueFormat bit2) +{ + char *errfmt = "Class1Record%s"; + void *errret = NULL; + OTF_Class1Record *rec; + int i, j; + + OTF_MALLOC (rec, num1, ""); + for (i = 0; i < num1; i++) + { + OTF_CALLOC (rec[i].Class2Record, num2, " (Class2Record)"); + for (j = 0; j < num2; j++) + { + if (read_value_record (otf, stream, offset, + bit1, &rec[i].Class2Record[j].Value1) < 0 + || read_value_record (otf, stream, offset, + bit2, &rec[i].Class2Record[j].Value2) < 0) + return NULL; + } + } + return rec; +} + + +static int +read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, + long offset, unsigned type, + OTF_LookupSubTable *subtable) +{ + char *errfmt = "GPOS LookupSubTable%s"; + int errret = -1; + + SEEK_STREAM (stream, offset); + READ_UINT16 (stream, subtable->Format); + switch (type) + { + case 1: +#if 0 + if (subtable->Format == 1) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + subtable->sub.gsub.single1.DeltaGlyphID = READ_INT16 (stream); + } + else if (subtable->Format == 2) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + subtable->sub.gsub.single2.GlyphCount + = read_glyph_ids (otf, stream, + &subtable->sub.gsub.single2.Substitute, 0); + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); +#endif + break; + + case 2: + if (subtable->Format == 1) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + } + else if (subtable->Format == 2) + { + SEEK_STREAM (stream, offset + 2); + read_coverage (otf, stream, offset, &subtable->Coverage); + READ_UINT16 (stream, subtable->sub.gpos.pair2.ValueFormat1); + READ_UINT16 (stream, subtable->sub.gpos.pair2.ValueFormat2); + read_class_def (otf, stream, offset, + &subtable->sub.gpos.pair2.ClassDef1); + read_class_def (otf, stream, offset, + &subtable->sub.gpos.pair2.ClassDef2); + READ_UINT16 (stream, subtable->sub.gpos.pair2.Class1Count); + READ_UINT16 (stream, subtable->sub.gpos.pair2.Class2Count); + subtable->sub.gpos.pair2.Class1Record + = read_class1_record_list (otf, stream, offset, + subtable->sub.gpos.pair2.Class1Count, + subtable->sub.gpos.pair2.ValueFormat1, + subtable->sub.gpos.pair2.Class2Count, + subtable->sub.gpos.pair2.ValueFormat2); + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 4: + if (subtable->Format == 1) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + read_coverage (otf, stream, offset, + &subtable->sub.gpos.mark_base1.BaseCoverage); + READ_UINT16 (stream, subtable->sub.gpos.mark_base1.ClassCount); + read_mark_array (otf, stream, offset, + &subtable->sub.gpos.mark_base1.MarkArray); + read_base_array (otf, stream, offset, + subtable->sub.gpos.mark_base1.ClassCount, + &subtable->sub.gpos.mark_base1.BaseArray); + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 6: +#if 0 + if (subtable->Format == 1) + { + read_coverage (otf, stream, offset, + &subtable->sub.gsub.chain_context1.Coverage); + subtable->sub.gsub.chain_context1.ChainSubRuleSetCount + = (read_chain_subrule_set + (otf, stream, offset, + &subtable->sub.gsub.chain_context1.ChainSubRuleSet)); + } + else if (subtable->Format == 2) + { + read_coverage (otf, stream, offset, + &subtable->sub.gsub.chain_context2.Coverage); + read_class_def (otf, stream, offset, + &subtable->sub.gsub.chain_context2.Backtrack); + read_class_def (otf, stream, offset, + &subtable->sub.gsub.chain_context2.Input); + read_class_def (otf, stream, offset, + &subtable->sub.gsub.chain_context2.LookAhead); + subtable->sub.gsub.chain_context2.ChainSubClassSetCnt + = (read_chain_subclass_set + (otf, stream, offset, + &subtable->sub.gsub.chain_context2.ChainSubClassSet)); + } + else if (subtable->Format == 3) + { + subtable->sub.gsub.chain_context3.BacktrackGlyphCount + = (read_coverage_list + (otf, stream, offset, + &subtable->sub.gsub.chain_context3.Backtrack)); + subtable->sub.gsub.chain_context3.InputGlyphCount + = (read_coverage_list + (otf, stream, offset, + &subtable->sub.gsub.chain_context3.Input)); + subtable->sub.gsub.chain_context3.LookaheadGlyphCount + = (read_coverage_list + (otf, stream, offset, + &subtable->sub.gsub.chain_context3.LookAhead)); + subtable->sub.gsub.chain_context3.SubstCount + = (read_subst_lookup_record + (otf, stream, + &subtable->sub.gsub.chain_context3.SubstLookupRecord)); + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); +#endif + + default: + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)"); + } + return 0; +} + + +static void * +read_gpos_table (OTF *otf, OTF_Stream *stream) +{ + char *errfmt = "GPOS%s"; + void *errret = NULL; + OTF_GPOS *gpos; + + OTF_CALLOC (gpos, 1, ""); + READ_FIXED (stream, gpos->Version); + READ_OFFSET (stream, gpos->ScriptList.offset); + READ_OFFSET (stream, gpos->FeatureList.offset); + READ_OFFSET (stream, gpos->LookupList.offset); + + if (read_script_list (otf, stream, gpos->ScriptList.offset, + &gpos->ScriptList) < 0 + || read_feature_list (otf, stream, gpos->FeatureList.offset, + &gpos->FeatureList) < 0 + || read_lookup_list (otf, stream, gpos->LookupList.offset, + &gpos->LookupList, 0) < 0) + return NULL; + return gpos; +} + + +#if 0 +/* BASE */ + +static OTF_BASE * +read_base_table (OTF_Stream *stream, long offset) +{ + OTF_BASE *base; + + OTF_MALLOC (base, 1); + + return base; +} + + +/* JSTF */ + +static OTF_JSTF * +read_jstf_table (OTF_Stream *stream, long offset) +{ + OTF_JSTF *jstf; + + OTF_MALLOC (jstf, 1); + + return jstf; +} +#endif + +/* GDEF */ +static int +read_attach_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_AttachList *list) +{ + char *errfmt = "AttachList%s"; + int errret = -1; + int i, j; + + if (read_coverage (otf, stream, offset, &list->Coverage) < 0) + return -1; + READ_UINT16 (stream, list->GlyphCount); + OTF_MALLOC (list->AttachPoint, list->GlyphCount, ""); + for (i = 0; i < list->GlyphCount; i++) + READ_OFFSET (stream, list->AttachPoint[i].offset); + for (i = 0; i < list->GlyphCount; i++) + { + int count; + + SEEK_STREAM (stream, offset + list->AttachPoint[i].offset); + READ_UINT16 (stream, count); + list->AttachPoint[i].PointCount = count; + OTF_MALLOC (list->AttachPoint[i].PointIndex, count, " (PointIndex)"); + for (j = 0; j < count; j++) + READ_UINT16 (stream, list->AttachPoint[i].PointIndex[j]); + } + return 0; +} + +static int +read_caret_value (OTF *otf, OTF_Stream *stream, long offset, + OTF_CaretValue *caret) +{ + char *errfmt = "CaretValue%s"; + int errret = -1; + + SEEK_STREAM (stream, offset + caret->offset); + READ_UINT16 (stream, caret->CaretValueFormat); + if (caret->CaretValueFormat == 1) + READ_INT16 (stream, caret->f.f1.Coordinate); + else if (caret->CaretValueFormat == 2) + READ_UINT16 (stream, caret->f.f2.CaretValuePoint); + else if (caret->CaretValueFormat == 3) + { + READ_INT16 (stream, caret->f.f3.Coordinate); + if (read_device_table (otf, stream, offset + caret->offset, + &caret->f.f3.DeviceTable) < 0) + return -1; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); + return 0; +} + +static int +read_lig_caret_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_LigCaretList *list) +{ + char *errfmt = "LigCaretList%s"; + int errret = -1; + int i, j; + + if (read_coverage (otf, stream, offset, &list->Coverage) < 0) + return -1; + READ_UINT16 (stream, list->LigGlyphCount); + OTF_MALLOC (list->LigGlyph, list->LigGlyphCount, ""); + for (i = 0; i < list->LigGlyphCount; i++) + READ_OFFSET (stream, list->LigGlyph[i].offset); + for (i = 0; i < list->LigGlyphCount; i++) + { + int count; + + SEEK_STREAM (stream, offset + list->LigGlyph[i].offset); + READ_UINT16 (stream, count); + list->LigGlyph[i].CaretCount = count; + OTF_MALLOC (list->LigGlyph[i].CaretValue, count, " (CaretValue)"); + for (j = 0; j < count; j++) + READ_OFFSET (stream, list->LigGlyph[i].CaretValue[j].offset); + for (j = 0; j < count; j++) + if (read_caret_value (otf, stream, offset + list->LigGlyph[i].offset, + &list->LigGlyph[i].CaretValue[j]) < 0) + return -1; + } + return 0; +} + +static int +read_gdef_header (OTF_Stream *stream, OTF_GDEFHeader *header) +{ + int errret = -1; + + READ_FIXED (stream, header->Version); + READ_OFFSET (stream, header->GlyphClassDef); + READ_OFFSET (stream, header->AttachList); + READ_OFFSET (stream, header->LigCaretList); + READ_OFFSET (stream, header->MarkAttachClassDef); + return 0; +} + +static void * +read_gdef_table (OTF *otf, OTF_Stream *stream) +{ + char *errfmt = "GDEF%s"; + void *errret = NULL; + OTF_GDEF *gdef; + + OTF_CALLOC (gdef, 1, ""); + read_gdef_header (stream, (OTF_GDEFHeader *) &gdef->header); + if (gdef->header.GlyphClassDef) + { + gdef->glyph_class_def.offset = gdef->header.GlyphClassDef; + read_class_def_without_offset (otf, stream, &gdef->glyph_class_def); + } + if (gdef->header.AttachList) + read_attach_list (otf, stream, gdef->header.AttachList, + &gdef->attach_list); + if (gdef->header.LigCaretList) + read_lig_caret_list (otf, stream, gdef->header.LigCaretList, + &gdef->lig_caret_list); + if (gdef->header.MarkAttachClassDef) + { + gdef->mark_attach_class_def.offset = gdef->header.MarkAttachClassDef; + read_class_def_without_offset (otf, stream, &gdef->mark_attach_class_def); + } + + return gdef; +} + + + +/* cmap */ + +static void * +read_cmap_table (OTF *otf, OTF_Stream *stream) +{ + char *errfmt = "cmap%s"; + void *errret = NULL; + OTF_cmap *cmap; + int i; + + OTF_CALLOC (cmap, 1, ""); + READ_USHORT (stream, cmap->version); + READ_USHORT (stream, cmap->numTables); + OTF_MALLOC (cmap->EncodingRecord, cmap->numTables, ""); + for (i = 0; i < cmap->numTables; i++) + { + READ_USHORT (stream, cmap->EncodingRecord[i].platformID); + READ_USHORT (stream, cmap->EncodingRecord[i].encodingID); + READ_ULONG (stream, cmap->EncodingRecord[i].offset); + if (cmap->EncodingRecord[i].platformID == 3 + && cmap->EncodingRecord[i].encodingID == 1) + cmap->Unicode = cmap->EncodingRecord + i; + } + for (i = 0; i < cmap->numTables; i++) + { + unsigned format; + + SEEK_STREAM (stream, cmap->EncodingRecord[i].offset); + READ_USHORT (stream, format); + cmap->EncodingRecord[i].subtable.format = format; + READ_USHORT (stream, cmap->EncodingRecord[i].subtable.length); + if (format == 8 || format == 10 || format == 12) + { + READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length); + READ_ULONG (stream, cmap->EncodingRecord[i].subtable.language); + } + else + { + READ_USHORT (stream, cmap->EncodingRecord[i].subtable.language); + } + switch (format) + { + case 0: + { + OTF_MALLOC (cmap->EncodingRecord[i].subtable.f.f0, 1, + " (EncodingRecord)"); + READ_BYTES (stream, + cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray, + 256); + } + break; + + case 2: + break; + + case 4: + { + OTF_EncodingSubtable4 *sub4; + int segCount; + int j; + unsigned dummy; + + OTF_MALLOC (sub4, 1, " (EncodingSubtable4)"); + cmap->EncodingRecord[i].subtable.f.f4 = sub4; + READ_USHORT (stream, sub4->segCountX2); + segCount = sub4->segCountX2 / 2; + READ_USHORT (stream, sub4->searchRange); + READ_USHORT (stream, sub4->entrySelector); + READ_USHORT (stream, sub4->rangeShift); + OTF_MALLOC (sub4->segments, segCount, " (segCount)"); + for (j = 0; j < segCount; j++) + READ_USHORT (stream, sub4->segments[j].endCount); + READ_USHORT (stream, dummy); + for (j = 0; j < segCount; j++) + READ_USHORT (stream, sub4->segments[j].startCount); + for (j = 0; j < segCount; j++) + READ_SHORT (stream, sub4->segments[j].idDelta); + for (j = 0; j < segCount; j++) + { + unsigned off; + unsigned rest = 2 * (segCount - j); + + READ_USHORT (stream, off); + if (off == 0) + sub4->segments[j].idRangeOffset = 0xFFFF; + else + sub4->segments[j].idRangeOffset = (off - rest) / 2; + } + j = (cmap->EncodingRecord[i].subtable.length + - (14 + 2 * (segCount * 4 + 1))); + sub4->GlyphCount = j / 2; + OTF_MALLOC (sub4->glyphIdArray, sub4->GlyphCount, " (GlyphCount)"); + for (j = 0; j < sub4->GlyphCount; j++) + READ_USHORT (stream, sub4->glyphIdArray[j]); + } + } + } + return cmap; +} + + + +/* TABLE: name */ + +static char * +read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec, int bytes) +{ + char *errfmt = "nameID (%d)"; + void *errret = NULL; + OTF_StreamState state; + char *str; + int i; + int c; + + SAVE_STREAM (stream, state); + SEEK_STREAM (stream, stream->pos + rec->offset); + + if (bytes == 1) + { + OTF_MALLOC (str, rec->length + 1, (void *) rec->nameID); + READ_BYTES (stream, str, rec->length); + for (i = 0; i < rec->length; i++) + if (str[i] < 0) + str[i] = '?'; + } + else if (bytes == 2) + { + OTF_MALLOC (str, rec->length / 2 + 1, (void *) rec->nameID); + for (i = 0; i < rec->length / 2; i++) + { + READ_USHORT (stream, c); + if (c >= 128) + c = '?'; + str[i] = c; + } + } + else if (bytes == 4) + { + OTF_MALLOC (str, rec->length / 4 + 1, (void *) rec->nameID); + for (i = 0; i < rec->length / 4; i++) + { + READ_ULONG (stream, c); + if (c >= 128) + c = '?'; + str[i] = c; + } + } + str[i] = '\0'; + RESTORE_STREAM (stream, state); + return str; +} + +static void * +read_name_table (OTF *otf, OTF_Stream *stream) +{ + char *errfmt = "name%s"; + void *errret = NULL; + OTF_name *name; + int i; + + OTF_CALLOC (name, 1, ""); + READ_USHORT (stream, name->format); + READ_USHORT (stream, name->count); + READ_USHORT (stream, name->stringOffset); + OTF_MALLOC (name->nameRecord, name->count, ""); + for (i = 0; i < name->count; i++) + { + OTF_NameRecord *rec = name->nameRecord + i; + + READ_USHORT (stream, rec->platformID); + READ_USHORT (stream, rec->encodingID); + READ_USHORT (stream, rec->languageID); + READ_USHORT (stream, rec->nameID); + READ_USHORT (stream, rec->length); + READ_USHORT (stream, rec->offset); + } + for (i = 0; i < name->count; i++) + { + OTF_NameRecord *rec = name->nameRecord + i; + int nameID = rec->nameID; + + if (nameID <= OTF_max_nameID + && ! name->name[nameID]) + { + if (rec->platformID == 0) + name->name[nameID] = read_name (otf, stream, rec, + rec->encodingID <= 3 ? 2 : 4); + else if (rec->platformID == 1 + && rec->encodingID == 0) + name->name[nameID] = read_name (otf, stream, rec, 1); + else if (rec->platformID == 3 + && (rec->encodingID == 1 || rec->encodingID == 10)) + name->name[nameID] = read_name (otf, stream, + rec, rec->encodingID == 1 ? 2 : 4); + } + } + + return name; +} + + + +/* APIs */ + +/* We can't use memory allocation macros in the following functions + because those macros returns from the functions before freeing + memory previously allocated. */ + +OTF * +otf_open (char *otf_name) +{ + FILE *fp; + char *errfmt = "opening otf (%s)"; + void *errret = NULL; + OTF *otf; + + fp = fopen (otf_name, "r"); + if (! fp) + OTF_ERROR (OTF_ERROR_FILE, otf_name); + otf = calloc (1, sizeof (OTF)); + if (! otf) + OTF_ERROR (OTF_ERROR_MEMORY, "body allocation"); + otf->filename = strdup (otf_name); + if (! otf->filename) + { + otf_close (otf); + fclose (fp); + OTF_ERROR (OTF_ERROR_MEMORY, "filename allocation"); + } + + if (read_otf_header (otf, fp) < 0) + { + otf_close (otf); + fclose (fp); + return NULL; + } + + fclose (fp); + return otf; +} + + +void +otf_close (OTF *otf) +{ + OTF_InternalData *internal_data = otf->internal_data; + int i; + + if (otf->filename) + free (otf->filename); + if (otf->table_dirs) + free (otf->table_dirs); + if (internal_data) + { + OTF_MemoryRecord *memrec = internal_data->memory_record; + + if (internal_data->work_stream) + free_stream (internal_data->work_stream); + + if (internal_data->streams) + for (i = 0; i < otf->offset_table.numTables; i++) + if (internal_data->streams[i]) + free_stream (internal_data->streams[i]); + + while (memrec) + { + OTF_MemoryRecord *next = memrec->next; + + for (i = 0; i < memrec->used; i++) + free (memrec->memory[i]); + free (memrec); + memrec = next; + } + free (internal_data); + } +} + + +void * +otf_get_table (OTF *otf, OTF_Tag tag) +{ + char *errfmt = "OTF Table Read"; + void *errret = NULL; + OTF_InternalData *internal_data = otf->internal_data; + OTF_TableDirectory *tabledir = NULL; + void *(*reader) (OTF *otf, OTF_Stream *stream); + + if (tag == otf_tag ("head")) + tabledir = otf->head, reader = read_head_table; + else if (tag == otf_tag ("name")) + tabledir = otf->name, reader = read_name_table; + else if (tag == otf_tag ("cmap")) + tabledir = otf->cmap, reader = read_cmap_table; + else if (tag == otf_tag ("GDEF")) + tabledir = otf->gdef, reader = read_gdef_table; + else if (tag == otf_tag ("GSUB")) + tabledir = otf->gsub, reader = read_gsub_table; + else if (tag == otf_tag ("GPOS")) + tabledir = otf->gpos, reader = read_gpos_table; + else + OTF_ERROR (OTF_ERROR_TABLE, " (unsupported)"); + + if (! tabledir) + OTF_ERROR (OTF_ERROR_TABLE, " (not found)"); + if (! tabledir->stream) + OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)"); + if (! tabledir->table) + { + tabledir->table = (*reader) (otf, tabledir->stream); + if (! tabledir->table) + { + free_stream (tabledir->stream); + tabledir->stream = NULL; + OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)"); + } + } + return tabledir->table; +} diff --git a/src/otfutil.c b/src/otfutil.c new file mode 100644 index 0000000..5987227 --- /dev/null +++ b/src/otfutil.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#include "otf.h" + +static char *error_message; +int otf_error; + +static char *error_string[] = + { + "Memory shortage", + "File error", + "Invalid OTF table contents" + }; + +int +otf__error (int err, char *fmt, void *arg) +{ + if (! error_message) + error_message = (char *) malloc (256); + sprintf (error_message, "OTF-Error (%s): ", error_string[-err - 1]); + sprintf (error_message + strlen (error_message), fmt, arg); + otf_error = err; + return 0; +} + +void +otf_perror (char *prefix) +{ + if (otf_error < 0) + { + if (prefix) + fprintf (stderr, "%s %s\n", prefix, error_message); + else + fprintf (stderr, "%s\n", error_message); + } +} + + +OTF_Tag +otf_tag (char *str) +{ + unsigned char *p = (unsigned char *) str; + + if (! str) + return (OTF_Tag) 0; + return (OTF_Tag) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); +} + diff --git a/src/otfutil.h b/src/otfutil.h new file mode 100644 index 0000000..f181bf1 --- /dev/null +++ b/src/otfutil.h @@ -0,0 +1,5 @@ +#define OTF_ERROR(err, arg) \ + return (otf__error ((err), errfmt, (arg)), errret) + +extern int otf__error (int err, char *fmt, void *arg); + -- 1.7.10.4