AC_PROG_LIBTOOL
# Checks for libraries.
+AC_PATH_XTRA
# Checks for header files.
AC_HEADER_STDC
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.
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "otf.h"
}
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;
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);
static void
dump_gpos_table (int indent, OTF_GPOS *gpos)
{
+ if (! gpos)
+ return;
IPRINT ("(GPOS");
indent++;
IPRINT ("(Header");
static void
dump_gdef_table (int indent, OTF_GDEF *gdef)
{
+ if (! gdef)
+ return;
IPRINT ("(GDEF");
indent++;
dump_gdef_header (indent, &gdef->header);
}
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);
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
/* Version number of package */
#undef VERSION
+
+/* Define to 1 if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#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
-
-\f
-
-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;
-}
-
-\f
-
-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);
-}
-
-\f
-
-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;
-}
-
-
-\f
-/* 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;
-}
-
-\f
-/* 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;
-}
-
-\f
-#if 0
-/* BASE */
-
-static OTF_BASE *
-read_base_table (OTF_Stream *stream, long offset)
-{
- OTF_BASE *base;
-
- OTF_MALLOC (base, 1);
-
- return base;
-}
-
-\f
-/* JSTF */
-
-static OTF_JSTF *
-read_jstf_table (OTF_Stream *stream, long offset)
-{
- OTF_JSTF *jstf;
-
- OTF_MALLOC (jstf, 1);
-
- return jstf;
-}
-#endif
-\f
-/* 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);
-}
-
-
-\f
-
-/* 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);
-}
-
-\f
-
-/* 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);
-}
-
-\f
-
-/* 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;
-}
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#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;
-}
-
-\f
-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;
-}
-
-\f
-
-/* 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;
-}
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#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]);
-}
-
+++ /dev/null
-#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);
-
#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
/*** @} */
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;
/* 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. */
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}
+
+\f
+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;
+}
+
+\f
+
+/* 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;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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
+
+\f
+
+#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)
+
+
+\f
+
+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;
+}
+
+
+\f
+
+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;
+}
+
+\f
+
+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;
+}
+
+\f
+/* 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;
+}
+
+\f
+/* 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;
+}
+
+\f
+#if 0
+/* BASE */
+
+static OTF_BASE *
+read_base_table (OTF_Stream *stream, long offset)
+{
+ OTF_BASE *base;
+
+ OTF_MALLOC (base, 1);
+
+ return base;
+}
+
+\f
+/* JSTF */
+
+static OTF_JSTF *
+read_jstf_table (OTF_Stream *stream, long offset)
+{
+ OTF_JSTF *jstf;
+
+ OTF_MALLOC (jstf, 1);
+
+ return jstf;
+}
+#endif
+\f
+/* 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;
+}
+
+\f
+
+/* 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;
+}
+
+\f
+
+/* 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;
+}
+
+\f
+
+/* 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;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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]);
+}
+
--- /dev/null
+#define OTF_ERROR(err, arg) \
+ return (otf__error ((err), errfmt, (arg)), errret)
+
+extern int otf__error (int err, char *fmt, void *arg);
+