/* otfopen.c -- OpenType font reader.
-Copyright (C) 2003, 2004, 2005, 2006, 2008
+Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010
National Institute of Advanced Industrial Science and Technology (AIST)
Registration Number H15PRO167
#include <config.h>
#include "otf.h"
-#include "otferror.h"
+#include "internal.h"
#include FT_TRUETYPE_TABLES_H
(5) API miscellaneous
*/
+
+int debug_flag = -1;
+
+static void
+set_debug_flag ()
+{
+ debug_flag = getenv ("LIBOTF_DEBUG") != NULL;
+}
+
\f
/* (0) Stream handler
static void
free_stream (OTF_Stream *stream)
{
- free (stream->buf);
+ if (stream->buf)
+ free (stream->buf);
free (stream);
}
(stream)->pos += 2; \
} while (0)
+#define READ_UINT24(stream, var) \
+ do { \
+ STREAM_CHECK_SIZE ((stream), 3); \
+ (var) = (((stream)->buf[(stream)->pos ] << 16) \
+ | ((stream)->buf[(stream)->pos + 1] << 8) \
+ | (stream)->buf[(stream)->pos + 2]); \
+ (stream)->pos += 3; \
+ } while (0)
+
#define READ_ULONG(stream, var) \
do { \
STREAM_CHECK_SIZE ((stream), 4); \
OTF_Stream *stream;
};
+struct _OTF_ApplicationData
+{
+ char *id;
+ void *data;
+ void (*freer) (void *data);
+ struct _OTF_ApplicationData *next;
+};
+
+typedef struct _OTF_ApplicationData OTF_ApplicationData;
+
struct OTF_InternalData
{
/* Information about each OTF table. */
/* Records of allocated memories. */
OTF_MemoryRecord *memory_record;
-};
+ /* Root of application data chain. */
+ OTF_ApplicationData *app_data;
+};
static OTF_MemoryRecord *
allocate_memory_record (OTF *otf)
static int
read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec)
{
- char *errfmt = "nameID (%d)";
+ char errfmt[256];
int errret = -1;
OTF_StreamState state;
int ucs = 0;
int ascii = 0;
int i;
+ sprintf (errfmt, "nameID (%d)%%s", rec->nameID);
if (rec->platformID == 0)
ucs = (rec->encodingID <= 3) ? 2 : 4;
else if (rec->platformID == 1 && rec->encodingID == 0)
: rec->encodingID == 10 ? 4
: 0);
- OTF_MALLOC (rec->name, rec->length + 1, (void *) rec->nameID);
+ OTF_MALLOC (rec->name, rec->length + 1, "");
SAVE_STREAM (stream, state);
SEEK_STREAM (stream, stream->pos + rec->offset);
READ_BYTES (stream, rec->name, rec->length);
\f
/*** (1-4) "cmap" table */
+static OTF_EncodingSubtable14 *
+read_cmap_uvs_table (OTF *otf, OTF_Stream *stream, OTF_Offset offset)
+{
+ OTF_EncodingSubtable14 *sub14;
+ char *errfmt = "cmap-uvs%s";
+ void *errret = NULL;
+ unsigned nRecords;
+ unsigned i,j;
+
+ OTF_MALLOC (sub14, 1, " (EncodingSubtable14)");
+ READ_ULONG (stream, nRecords);
+ sub14->nRecords = nRecords;
+ OTF_MALLOC (sub14->Records, nRecords, "(EncodingSubtable14-Records)");
+ for (i = 0; i < sub14->nRecords; i++)
+ {
+ unsigned varSelector=0, defaultUVSOffset, nonDefaultUVSOffset;
+
+ READ_UINT24 (stream, varSelector);
+ sub14->Records[i].varSelector = varSelector;
+ READ_ULONG (stream, defaultUVSOffset);
+ sub14->Records[i].defaultUVSOffset = defaultUVSOffset;
+ READ_ULONG (stream, nonDefaultUVSOffset);
+ sub14->Records[i].nonDefaultUVSOffset = nonDefaultUVSOffset;
+ }
+ for (i = 0; i < sub14->nRecords; i++)
+ {
+ OTF_VariationSelectorRecord *record = &sub14->Records[i];
+ unsigned defaultUVSOffset = record->defaultUVSOffset;
+ unsigned nonDefaultUVSOffset = record->nonDefaultUVSOffset;
+
+ if (defaultUVSOffset)
+ {
+ unsigned numUnicodeValueRanges;
+
+ SEEK_STREAM (stream, offset+defaultUVSOffset);
+ READ_ULONG (stream, numUnicodeValueRanges);
+ record->numUnicodeValueRanges = numUnicodeValueRanges;
+ OTF_MALLOC (record->unicodeValueRanges,
+ numUnicodeValueRanges,
+ "(EncodingSubtable14-Records-unicodeValueRanges)");
+ for (j = 0; j < numUnicodeValueRanges; j++)
+ {
+ OTF_UnicodeValueRange *unicodeValueRange
+ = &record->unicodeValueRanges[j];
+ unsigned startUnicodeValue;
+ char additionalCount;
+
+ READ_UINT24 (stream, startUnicodeValue);
+ unicodeValueRange->startUnicodeValue=startUnicodeValue;
+ READ_BYTES (stream, &additionalCount, 1);
+ unicodeValueRange->additionalCount
+ = (unsigned short) additionalCount;
+ }
+ }
+ if (nonDefaultUVSOffset)
+ {
+ unsigned numUVSMappings;
+
+ SEEK_STREAM (stream, offset+nonDefaultUVSOffset);
+ READ_ULONG (stream, numUVSMappings);
+ record->numUVSMappings = numUVSMappings;
+ OTF_MALLOC (record->uvsMappings, numUVSMappings,
+ "(EncodingSubtable14-Records-uvsMappings)");
+ for (j = 0; j < numUVSMappings; j++)
+ {
+ OTF_UVSMapping *uvsMapping = &record->uvsMappings[j];
+ unsigned unicodeValue;
+ unsigned short glyphID;
+
+ READ_UINT24 (stream, unicodeValue);
+ uvsMapping->unicodeValue = unicodeValue;
+ READ_USHORT (stream, glyphID);
+ uvsMapping->glyphID = glyphID;
+ }
+ }
+ }
+ return sub14;
+}
+
static void *
read_cmap_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag)
{
unicode_full_index = i;
}
}
+ cmap->table_index = unicode_full_index;
+
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)
+ if (format == 14)
{
READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length);
- READ_ULONG (stream, cmap->EncodingRecord[i].subtable.language);
+ cmap->EncodingRecord[i].subtable.language = 0;
}
else
{
- READ_USHORT (stream, cmap->EncodingRecord[i].subtable.language);
+ 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)
{
{
unsigned off;
unsigned rest = 2 * (segCount - j);
-
+
READ_USHORT (stream, off);
if (off == 0)
sub4->segments[j].idRangeOffset = 0xFFFF;
}
break;
+ case 14:
+ {
+ cmap->EncodingRecord[i].subtable.f.f14
+ = read_cmap_uvs_table (otf, stream,
+ cmap->EncodingRecord[i].offset);
+ break;
+ }
+
default:
OTF_ERROR (OTF_ERROR_TABLE, " (invalid Subtable format)");
}
for (i = 0; i < segCount; i++)
{
- OTF_cmapSegument *seg = sub4->segments + i;
+ OTF_cmapSegment *seg = sub4->segments + i;
int c;
if (seg->idRangeOffset == 0xFFFF)
for (c = seg->startCount; c <= seg->endCount; c++)
{
- glyph_id = c + seg->idDelta;
+ glyph_id = (c + seg->idDelta) % 0x10000;
cmap->unicode_table[c] = glyph_id;
if (glyph_id > max_glyph_id)
max_glyph_id = glyph_id;
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)
+ if (stream->buf)
{
- gdef->mark_attach_class_def.offset = gdef->header.MarkAttachClassDef;
- read_class_def_without_offset (otf, stream, &gdef->mark_attach_class_def);
+ 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);
+ }
}
*table->address = gdef;
count = read_glyph_ids (otf, stream, &reverse_chain->Substitute, 0, -1);
if (count <= 0)
return -1;
- reverse_chain->GlyphCount = count;
+ reverse_chain->GlyphCount = count;
return 0;
}
OTF_Tag gsub_tag = OTF_tag ("GSUB");
OTF_Tag gpos_tag = OTF_tag ("GPOS");
OTF_Stream *stream = make_stream ("Offset Table");
+ unsigned char ttctag[4];
if (! stream)
return -1;
internal_data->header_stream = stream;
- /* Size of Offset Table is 12 bytes. */
- if (setup_stream (stream, fp, 0, 12) < 0)
+ /* Size of Offset Table is 12 bytes. Size of TTC header
+ (including only the an offset of the first font) is 16. */
+ if (setup_stream (stream, fp, 0, 16) < 0)
return -1;
+ READ_BYTES (stream, ttctag, 4);
+ if (memcmp (ttctag, "ttcf", 4) == 0)
+ {
+ /* This is a TrueType Collection file. We extract the first font. */
+ unsigned version, numfonts, offset;
+ READ_ULONG (stream, version);
+ READ_ULONG (stream, numfonts);
+ READ_ULONG (stream, offset); /* Offset of the first font. */
+ if (setup_stream (stream, fp, offset, 12) < 0)
+ return -1;
+ }
+ else
+ SEEK_STREAM (stream, 0L);
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) < 0)
+ if (setup_stream (stream, fp, stream->pos,
+ 16 * otf->offset_table.numTables) < 0)
return -1;
OTF_CALLOC (otf->table_dirs, otf->offset_table.numTables,
internal_data->table_info[OTF_TABLE_TYPE_GPOS].stream = stream;
}
+ if (! internal_data->table_info[OTF_TABLE_TYPE_GDEF].stream)
+ /* We can simulate the GDEF table. */
+ internal_data->table_info[OTF_TABLE_TYPE_GDEF].stream
+ = make_stream ("GDEF");
return 0;
}
int len = strlen (otf_name);
const char *ext = otf_name + (len - 4);
+ if (debug_flag < 0)
+ set_debug_flag ();
+
if (len < 4
|| ext[0] != '.'
- || (ext[1] != 'O' && ext[1] != 'T' && ext[1] != 'o' && ext[1] != 't')
- || (ext[2] != 'T' && ext[2] != 't')
- || (ext[3] != 'F' && ext[3] != 'f'))
+ || (strncasecmp (ext + 1, "otf", 3)
+ && strncasecmp (ext + 1, "ttf", 3)
+ && strncasecmp (ext + 1, "ttc", 3)))
OTF_ERROR (OTF_ERROR_FILE, otf_name);
fp = fopen (otf_name, "r");
if (! fp)
OTF *otf;
OTF_InternalData *internal_data;
+ if (debug_flag < 0)
+ set_debug_flag ();
+
if (! FT_IS_SFNT (face))
OTF_ERROR (OTF_ERROR_FILE, (char *) face->family_name);
otf = calloc (1, sizeof (OTF));
if (! otf)
OTF_ERROR (OTF_ERROR_MEMORY, "body allocation");
otf->filename = NULL;
-
+
internal_data = calloc (1, sizeof (OTF_InternalData));
if (! internal_data)
OTF_ERROR (OTF_ERROR_MEMORY, " (InternalData");
if (internal_data)
{
OTF_MemoryRecord *memrec = internal_data->memory_record;
+ OTF_ApplicationData *app_data = internal_data->app_data;
if (internal_data->header_stream)
free_stream (internal_data->header_stream);
if (internal_data->table_info[i].stream)
free_stream (internal_data->table_info[i].stream);
+ for (; app_data; app_data = app_data->next)
+ if (app_data->data && app_data->freer)
+ app_data->freer (app_data->data);
+
while (memrec)
{
OTF_MemoryRecord *next = memrec->next;
free (memrec);
memrec = next;
}
+
free (internal_data);
}
if (otf->filename)
if (OTF_get_features (otf, gsubp) < 0)
{
+ if (gsubp ? ! otf->gsub : ! otf->gpos)
+ return 0;
for (i = 0; i < n_features; i++)
{
OTF_Tag feature = features[i];
if ((((unsigned) feature) & 0x80000000) == 0)
return -1;
}
- return 1;
}
if (gsubp)
{
name[3] = (char) (tag & 0xFF);
name[4] = '\0';
}
+
+int
+OTF_put_data (OTF *otf, char *id, void *data, void (*freer) (void *data))
+{
+ char *errfmt = "appdata %s";
+ int errret = -1;
+ OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data;
+ OTF_ApplicationData *app_data = internal_data->app_data;
+ int len = strlen (id) + 1;
+
+ for (; app_data; app_data = app_data->next)
+ if (memcmp (app_data->id, id, len) == 0)
+ {
+ if (app_data->data && app_data->freer)
+ app_data->freer (app_data->data);
+ break;
+ }
+ if (! app_data)
+ {
+ OTF_MALLOC (app_data, sizeof (OTF_ApplicationData), id);
+ app_data->next = internal_data->app_data;
+ internal_data->app_data = app_data;
+ OTF_MALLOC (app_data->id, len, id);
+ memcpy (app_data->id, id, len);
+ }
+ app_data->data = data;
+ app_data->freer = freer;
+ return 0;
+}
+
+void *
+OTF_get_data (OTF *otf, char *id)
+{
+ OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data;
+ OTF_ApplicationData *app_data = internal_data->app_data;
+
+ for (; app_data; app_data = app_data->next)
+ if (strcmp (app_data->id, id) == 0)
+ return app_data->data;
+ return NULL;
+}