(match_ids_backward): New function.
[m17n/libotf.git] / src / otfopen.c
index ea0445b..c49eb1d 100644 (file)
@@ -1,6 +1,6 @@
 /* otfopen.c -- OpenType font reader.
 
 /* otfopen.c -- OpenType font reader.
 
-Copyright (C) 2003, 2004, 2005, 2006
+Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009
   National Institute of Advanced Industrial Science and Technology (AIST)
   Registration Number H15PRO167
 
   National Institute of Advanced Industrial Science and Technology (AIST)
   Registration Number H15PRO167
 
@@ -57,6 +57,15 @@ write to the Free Software Foundation, Inc., 59 Temple Place, Suite
 
     (5) API miscellaneous
 */
 
     (5) API miscellaneous
 */
+
+int debug_flag = -1;
+
+static void
+set_debug_flag ()
+{
+  debug_flag = getenv ("LIBOTF_DEBUG") != NULL;
+}
+
 \f
 /* (0) Stream handler
 
 \f
 /* (0) Stream handler
 
@@ -91,7 +100,7 @@ typedef struct
 
 typedef long OTF_StreamState;
 
 
 typedef long OTF_StreamState;
 
-OTF_Stream *
+static OTF_Stream *
 make_stream (const char *name)
 {
   OTF_Stream *stream;
 make_stream (const char *name)
 {
   OTF_Stream *stream;
@@ -105,7 +114,7 @@ make_stream (const char *name)
   return stream;
 }
 
   return stream;
 }
 
-int
+static int
 setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes)
 {
   char *errfmt = "stream setup for %s";
 setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes)
 {
   char *errfmt = "stream setup for %s";
@@ -131,7 +140,7 @@ setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes)
   return 0;
 }
 
   return 0;
 }
 
-OTF_Stream *
+static OTF_Stream *
 make_stream_from_ft_face (FT_Face face, const char *name)
 {
   char *errfmt = "FT_Face stream creation for %s";
 make_stream_from_ft_face (FT_Face face, const char *name)
 {
   char *errfmt = "FT_Face stream creation for %s";
@@ -161,10 +170,11 @@ make_stream_from_ft_face (FT_Face face, const char *name)
   return stream;
 }
 
   return stream;
 }
 
-void
+static void
 free_stream (OTF_Stream *stream)
 {
 free_stream (OTF_Stream *stream)
 {
-  free (stream->buf);
+  if (stream->buf)
+    free (stream->buf);
   free (stream);
 }
 
   free (stream);
 }
 
@@ -199,6 +209,15 @@ free_stream (OTF_Stream *stream)
     (stream)->pos += 2;                                                \
   } while (0)
 
     (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);                   \
 #define READ_ULONG(stream, var)                                \
   do {                                                 \
     STREAM_CHECK_SIZE ((stream), 4);                   \
@@ -289,6 +308,16 @@ struct _OTF_TableInfo
   OTF_Stream *stream;
 };
 
   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.  */
 struct OTF_InternalData
 {
   /* Information about each OTF table.  */
@@ -299,6 +328,9 @@ struct OTF_InternalData
 
   /* Records of allocated memories.  */
   OTF_MemoryRecord *memory_record;
 
   /* Records of allocated memories.  */
   OTF_MemoryRecord *memory_record;
+
+  /* Root of application data chain.  */
+  OTF_ApplicationData *app_data;
 };
 
 
 };
 
 
@@ -382,13 +414,14 @@ read_head_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag)
 static int
 read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec)
 {
 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;
 
   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)
   if (rec->platformID == 0)
     ucs = (rec->encodingID <= 3) ? 2 : 4;
   else if (rec->platformID == 1 && rec->encodingID == 0)
@@ -398,7 +431,7 @@ read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec)
           : rec->encodingID == 10 ? 4
           : 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);
   SAVE_STREAM (stream, state);
   SEEK_STREAM (stream, stream->pos + rec->offset);
   READ_BYTES (stream, rec->name, rec->length);
@@ -495,6 +528,85 @@ read_name_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag)
 \f
 /*** (1-4) "cmap" table */
 
 \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)
 {
 static void *
 read_cmap_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag)
 {
@@ -533,6 +645,8 @@ read_cmap_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag)
            unicode_full_index = i;
        }
     }
            unicode_full_index = i;
        }
     }
+  cmap->table_index = unicode_full_index;
+
   for (i = 0; i < cmap->numTables; i++)
     {
       unsigned format;
   for (i = 0; i < cmap->numTables; i++)
     {
       unsigned format;
@@ -540,15 +654,23 @@ read_cmap_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag)
       SEEK_STREAM (stream, cmap->EncodingRecord[i].offset);
       READ_USHORT (stream, format);
       cmap->EncodingRecord[i].subtable.format = 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);
+         READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length);     
+         cmap->EncodingRecord[i].subtable.language = 0;
        }
       else
        {
        }
       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)
        {
        }
       switch (format)
        {
@@ -705,6 +827,14 @@ read_cmap_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag)
          }
          break;
 
          }
          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)");
        }
        default:
          OTF_ERROR (OTF_ERROR_TABLE, " (invalid Subtable format)");
        }
@@ -725,13 +855,13 @@ read_cmap_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag)
 
            for (i = 0; i < segCount; i++)
              {
 
            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++)
                    {
                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;
                      cmap->unicode_table[c] = glyph_id;
                      if (glyph_id > max_glyph_id)
                        max_glyph_id = glyph_id;
@@ -951,41 +1081,48 @@ read_device_table (OTF *otf, OTF_Stream *stream, long offset,
   READ_UINT16 (stream, table->EndSize);
   READ_UINT16 (stream, table->DeltaFormat);
   num = table->EndSize - table->StartSize + 1;
   READ_UINT16 (stream, table->EndSize);
   READ_UINT16 (stream, table->DeltaFormat);
   num = table->EndSize - table->StartSize + 1;
-  OTF_MALLOC (table->DeltaValue, num, "");
+  if (num > 0 && table->DeltaFormat >= 1 && table->DeltaFormat <= 3)
+    {
+      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)
+      if (table->DeltaFormat == 1)
+       for (i = 0; i < num; i++)
          {
          {
-           READ_UINT16 (stream, val);
-           intval.int8 = val >> 8;
-           table->DeltaValue[i] = intval.int8;
+           if ((i % 8) == 0)
+             READ_UINT16 (stream, val);
+           intval.int2 = (val >> (14 - (i % 8) * 2)) & 0x03;
+           table->DeltaValue[i] = intval.int2;
          }
          }
-       else
+      else if (table->DeltaFormat == 2)
+       for (i = 0; i < num; i++)
          {
          {
-           intval.int8 = val >> 8;
-           table->DeltaValue[i] = intval.int8;
+           if ((i % 4) == 0)
+             READ_UINT16 (stream, val);
+           intval.int4 = (val >> (12 - (i % 4) * 4)) & 0x0F;
+           table->DeltaValue[i] = intval.int4;
          }
          }
-      }
+      else                             /* (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
   else
-    OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)");
+    {
+      /* Invalid DeltaFormat but several fonts has such values (bug of
+        fontforge?).  So accept it with NULL delta values.  */
+      table->DeltaValue = NULL;
+    }
   return 0;
 }
 
   return 0;
 }
 
@@ -1099,22 +1236,27 @@ read_gdef_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag)
   OTF_GDEF *gdef;
 
   OTF_CALLOC (gdef, 1, "");
   OTF_GDEF *gdef;
 
   OTF_CALLOC (gdef, 1, "");
-  read_gdef_header (stream, (OTF_GDEFHeader *) &gdef->header);
-  if (gdef->header.GlyphClassDef)
+  if (stream->buf)
     {
     {
-      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);
+      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;
     }
 
   *table->address = gdef;
@@ -2604,7 +2746,7 @@ read_jstf_table (OTF_Stream *stream, long offset)
 \f
 /*** (1-11) Structure for OTF */
 
 \f
 /*** (1-11) Structure for OTF */
 
-int
+static int
 read_offset_table (OTF *otf, OTF_Stream *stream, OTF_OffsetTable *table)
 {
   int errret = -1;
 read_offset_table (OTF *otf, OTF_Stream *stream, OTF_OffsetTable *table)
 {
   int errret = -1;
@@ -2735,6 +2877,10 @@ read_header_part (OTF *otf, FILE *fp, FT_Face face)
        internal_data->table_info[OTF_TABLE_TYPE_GPOS].stream = stream;
     }
 
        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;
 }
 
   return 0;
 }
 
@@ -2796,6 +2942,9 @@ OTF_open (const char *otf_name)
   int len = strlen (otf_name);
   const char *ext = otf_name + (len - 4);
 
   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')
   if (len < 4
       || ext[0] != '.'
       || (ext[1] != 'O' && ext[1] != 'T' && ext[1] != 'o' && ext[1] != 't')
@@ -2846,6 +2995,9 @@ OTF_open_ft_face (FT_Face face)
   OTF *otf;
   OTF_InternalData *internal_data;
 
   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 (! FT_IS_SFNT (face))
     OTF_ERROR (OTF_ERROR_FILE, (char *) face->family_name);
   otf = calloc (1, sizeof (OTF));
@@ -2880,6 +3032,7 @@ OTF_close (OTF *otf)
   if (internal_data)
     {
       OTF_MemoryRecord *memrec = internal_data->memory_record;
   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->header_stream)
        free_stream (internal_data->header_stream);
@@ -2888,6 +3041,10 @@ OTF_close (OTF *otf)
        if (internal_data->table_info[i].stream)
          free_stream (internal_data->table_info[i].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;
       while (memrec)
        {
          OTF_MemoryRecord *next = memrec->next;
@@ -2897,6 +3054,7 @@ OTF_close (OTF *otf)
          free (memrec);
          memrec = next;
        }
          free (memrec);
          memrec = next;
        }
+
       free (internal_data);
     }
   if (otf->filename)
       free (internal_data);
     }
   if (otf->filename)
@@ -3092,3 +3250,44 @@ OTF_tag_name (OTF_Tag tag, char *name)
   name[3] = (char) (tag & 0xFF);
   name[4] = '\0';
 }
   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;
+}