(gstring_subst): Correctly set temp.f.index.
[m17n/libotf.git] / src / otfopen.c
index 94429ec..54091d0 100644 (file)
@@ -337,52 +337,74 @@ read_head_table (OTF *otf, OTF_Stream *stream)
 \f
 /*** (1-3) "name" table */
 
-static char *
-read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec, int bytes)
+static int
+read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec)
 {
   char *errfmt = "nameID (%d)";
-  void *errret = NULL;
+  int errret = -1;
   OTF_StreamState state;
-  char *str;
+  int ucs = 0;
+  int ascii = 0;
   int i;
-  int c;
 
+  if (rec->platformID == 0)
+    ucs = (rec->encodingID <= 3) ? 2 : 4;
+  else if (rec->platformID == 1 && rec->encodingID == 0)
+    ascii = 1;
+  else if (rec->platformID == 3)
+    ucs = (rec->encodingID == 1  ? 2
+          : rec->encodingID == 10 ? 4
+          : 0);
+
+  OTF_MALLOC (rec->name, rec->length + 1, (void *) rec->nameID);
   SAVE_STREAM (stream, state);
   SEEK_STREAM (stream, stream->pos + rec->offset);
+  READ_BYTES (stream, rec->name, rec->length);
+  RESTORE_STREAM (stream, state);
+  rec->name[rec->length] = 0;
 
-  if (bytes == 1)
+  if (ascii)
     {
-      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] = '?';
+      rec->ascii = 1;
     }
-  else if (bytes == 2)
+  else if (ucs == 2)
     {
-      OTF_MALLOC (str, rec->length / 2 + 1, (void *) rec->nameID);
+      rec->ascii = 1;
       for (i = 0; i < rec->length / 2; i++)
        {
-         READ_USHORT (stream, c);
-         if (c >= 128)
-           c = '?';
-         str[i] = c;
+         if (rec->name[i * 2] > 0
+             || rec->name[i * 2 + 1] >= 128)
+           {
+             rec->ascii = 0;
+             break;
+           }
        }
+      if (rec->ascii)
+       for (i = 0; i < rec->length / 2; i++)
+         rec->name[i] = rec->name[i * 2 + 1];
+      rec->name[i] = 0;
     }
-  else if (bytes == 4)
+  else if (ucs == 4)
     {
-      OTF_MALLOC (str, rec->length / 4 + 1, (void *) rec->nameID);
+      rec->ascii = 1;
       for (i = 0; i < rec->length / 4; i++)
        {
-         READ_ULONG (stream, c);
-         if (c >= 128)
-           c = '?';
-         str[i] = c;
+         if (rec->name[i * 4] > 0
+             || rec->name[i * 4 + 1] > 0
+             || rec->name[i * 4 + 2] > 0
+             || rec->name[i * 2 + 3] >= 128)
+           {
+             rec->ascii = 0;
+             break;
+           }
        }
+      if (rec->ascii)
+       for (i = 0; i < rec->length / 4; i++)
+         rec->name[i] = rec->name[i * 4 + 3];
+      rec->name[i] = 0;
     }
-  str[i] = '\0';
-  RESTORE_STREAM (stream, state);
-  return str;
+
+  return 0;
 }
 
 static void *
@@ -414,20 +436,13 @@ read_name_table (OTF *otf, OTF_Stream *stream)
       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);
-       }
+      read_name (otf, stream, rec);
+
+      if (nameID >= OTF_max_nameID)
+       continue;
+      if (! name->name[nameID]
+         && rec->ascii)
+       name->name[nameID] = (char *) rec->name;
     }
 
   return name;
@@ -442,7 +457,7 @@ read_cmap_table (OTF *otf, OTF_Stream *stream)
   char *errfmt = "cmap%s";
   void *errret = NULL;
   OTF_cmap *cmap;
-  int unicode_index = -1;
+  int unicode_bmp_index = -1, unicode_full_index = -1;
   int i;
 
   OTF_CALLOC (cmap, 1, "");
@@ -451,12 +466,27 @@ read_cmap_table (OTF *otf, OTF_Stream *stream)
   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);
+      unsigned platformID, encodingID;
+
+      READ_USHORT (stream, platformID);
+      cmap->EncodingRecord[i].platformID = platformID;
+      READ_USHORT (stream, encodingID);
+      cmap->EncodingRecord[i].encodingID = encodingID;
       READ_ULONG (stream, cmap->EncodingRecord[i].offset);
-      if (cmap->EncodingRecord[i].platformID == 3
-         && cmap->EncodingRecord[i].encodingID == 1)
-       unicode_index = i;
+      if (platformID == 0)
+       {
+         if (encodingID <= 3)
+           unicode_bmp_index = i;
+         else
+           unicode_full_index = i;
+       }
+      else if (platformID == 3)
+       {
+         if (encodingID == 1)
+           unicode_bmp_index = i;
+         else if (encodingID == 10)
+           unicode_full_index = i;
+       }
     }
   for (i = 0; i < cmap->numTables; i++)
     {
@@ -488,6 +518,36 @@ read_cmap_table (OTF *otf, OTF_Stream *stream)
          break;
 
        case 2:
+         {
+           OTF_EncodingSubtable2 *sub2;
+           int j, max_key, remaining_bytes;
+
+           OTF_MALLOC (sub2, 1, " (EncodingSubtable2)");
+           cmap->EncodingRecord[i].subtable.f.f2 = sub2;
+           for (j = 0, max_key = 0; j < 256; j++)
+             {
+               READ_USHORT (stream, sub2->subHeaderKeys[j]);
+               if (max_key < sub2->subHeaderKeys[j])
+                 max_key = sub2->subHeaderKeys[j];
+             }
+           max_key += 8;
+           sub2->subHeaderCount = max_key / 8;
+           OTF_MALLOC (sub2->subHeaders, max_key / 8, " (subHeaders)");
+           for (j = 0; j < sub2->subHeaderCount; j++)
+             {
+               READ_USHORT (stream, sub2->subHeaders[j].firstCode);
+               READ_USHORT (stream, sub2->subHeaders[j].entryCount);
+               READ_SHORT (stream, sub2->subHeaders[j].idDelta);
+               READ_USHORT (stream, sub2->subHeaders[j].idRangeOffset);
+               /* Make it offset from sub2->glyphIndexArray.  */
+               sub2->subHeaders[j].idRangeOffset -= max_key - (j * 8 + 6);
+             }
+           sub2->glyphIndexCount = (cmap->EncodingRecord[i].subtable.length
+                                    - 262 - max_key);
+           OTF_MALLOC (sub2->glyphIndexArray, sub2->glyphIndexCount,
+                       " (glyphIndexArray)");
+           READ_BYTES (stream, sub2->glyphIndexArray, sub2->glyphIndexCount);
+         }
          break;
 
        case 4:
@@ -545,12 +605,69 @@ read_cmap_table (OTF *otf, OTF_Stream *stream)
            for (j = 0; j < sub6->entryCount; j++)
              READ_USHORT (stream, sub6->glyphIdArray[j]);
          }
+         break;
+
+       case 8:
+         {
+           OTF_EncodingSubtable8 *sub8;
+           int j;
+
+           OTF_MALLOC (sub8, 1, " (EncodingSubtable8)");
+           cmap->EncodingRecord[i].subtable.f.f8 = sub8;
+           for (j = 0; j < 8192; j++)
+             READ_BYTES (stream, sub8->is32, 8192);
+           READ_ULONG (stream, sub8->nGroups);
+           OTF_MALLOC (sub8->Groups, sub8->nGroups, " (Groups)");
+           for (j = 0; j < sub8->nGroups; j++)
+             {
+               READ_ULONG (stream, sub8->Groups[i].startCharCode);
+               READ_ULONG (stream, sub8->Groups[i].endCharCode);
+               READ_ULONG (stream, sub8->Groups[i].startGlyphID);
+             }
+         }
+         break;
+
+       case 10:
+         {
+           OTF_EncodingSubtable10 *sub10;
+           int j;
+
+           OTF_MALLOC (sub10, 1, " (EncodingSubtable10)");
+           cmap->EncodingRecord[i].subtable.f.f10 = sub10;
+           READ_ULONG (stream, sub10->startCharCode);
+           READ_ULONG (stream, sub10->numChars);
+           OTF_MALLOC (sub10->glyphs, sub10->numChars, " (GlyphCount)");
+           for (j = 0; j < sub10->numChars; j++)
+             READ_USHORT (stream, sub10->glyphs[j]);
+         }
+         break;
+
+       case 12:
+         {
+           OTF_EncodingSubtable12 *sub12;
+           int j;
+
+           OTF_MALLOC (sub12, 1, " (EncodingSubtable12)");
+           cmap->EncodingRecord[i].subtable.f.f12 = sub12;
+           READ_ULONG (stream, sub12->nGroups);
+           OTF_MALLOC (sub12->Groups, sub12->nGroups, " (Groups)");
+           for (j = 0; j < sub12->nGroups; j++)
+             {
+               READ_ULONG (stream, sub12->Groups[i].startCharCode);
+               READ_ULONG (stream, sub12->Groups[i].endCharCode);
+               READ_ULONG (stream, sub12->Groups[i].startGlyphID);
+             }
+         }
+         break;
+
+       default:
+         OTF_ERROR (OTF_ERROR_TABLE, " (invalid Subtable format)");
        }
     }
 
-  if (unicode_index >= 0)
+  if (unicode_bmp_index >= 0)
     {
-      OTF_EncodingRecord *rec = cmap->EncodingRecord + unicode_index;
+      OTF_EncodingRecord *rec = cmap->EncodingRecord + unicode_bmp_index;
       OTF_GlyphID glyph_id, max_glyph_id = 0;
 
       OTF_CALLOC (cmap->unicode_table, 0x10000, "");
@@ -1263,7 +1380,7 @@ read_class_set_list (OTF *otf, OTF_Stream *stream, long offset,
   READ_UINT16 (stream, count);
   if (! count)
     OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
-  OTF_MALLOC (*set, count, "");
+  OTF_CALLOC (*set, count, "");
   for (i = 0; i < count; i++)
     /* Offset can be zero.  */
     READ_OFFSET (stream, (*set)[i].offset);
@@ -1870,6 +1987,7 @@ read_value_record (OTF *otf, OTF_Stream *stream, long offset,
   OTF_StreamState state;
   int size, i;
 
+  memset (value_record, 0, sizeof (OTF_ValueRecord));
   if (! bit)
     return 0;
   for (i = 0, size = 0; i < 8; i++)
@@ -1878,7 +1996,7 @@ read_value_record (OTF *otf, OTF_Stream *stream, long offset,
 
   if (bit & OTF_XPlacement)
     READ_INT16 (stream, value_record->XPlacement);
-  if (bit & OTF_XPlacement)
+  if (bit & OTF_YPlacement)
     READ_INT16 (stream, value_record->YPlacement);
   if (bit & OTF_XAdvance)
     READ_INT16 (stream, value_record->XAdvance);
@@ -2124,9 +2242,16 @@ read_ligature_attach (OTF *otf, OTF_Stream *stream, long offset,
     }
   for (i = 0; i < attach->ComponentCount; i++)
     for (j = 0; j < ClassCount; j++)
-      if (read_anchor (otf, stream, offset + attach->offset,
-                      &attach->ComponentRecord[i].LigatureAnchor[j]) < 0)
-       return -1;
+      {
+       if (attach->ComponentRecord[i].LigatureAnchor[j].offset)
+         {
+           if (read_anchor (otf, stream, offset + attach->offset,
+                            &attach->ComponentRecord[i].LigatureAnchor[j]) < 0)
+             return -1;
+         }
+       else
+         attach->ComponentRecord[i].LigatureAnchor[j].AnchorFormat = 0;
+      }
   return 0;
 }
 
@@ -2169,6 +2294,8 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
     case 1:
       if (subtable->Format == 1)
        {
+         if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
+           return -1;
          READ_UINT16 (stream, subtable->u.single1.ValueFormat);
          read_value_record (otf, stream, offset,
                             subtable->u.single1.ValueFormat,
@@ -2179,6 +2306,8 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
          OTF_GPOS_Single2 *single2 = &subtable->u.single2;
          int i;
 
+         if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
+           return -1;
          READ_UINT16 (stream, single2->ValueFormat);
          READ_UINT16 (stream, single2->ValueCount);
          OTF_CALLOC (single2->Value, single2->ValueCount," (ValueRecord)");
@@ -2576,7 +2705,15 @@ OTF_open (char *otf_name)
   void *errret = NULL;
   OTF *otf;
   OTF_InternalData *internal_data;
-
+  int len = strlen (otf_name);
+  const char *ext = otf_name + (len - 4);
+
+  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'))
+    OTF_ERROR (OTF_ERROR_FILE, otf_name);
   fp = fopen (otf_name, "r");
   if (! fp)
     OTF_ERROR (OTF_ERROR_FILE, otf_name);
@@ -2643,6 +2780,8 @@ OTF_close (OTF *otf)
        }
       free (internal_data);
     }
+  if (otf->filename)
+    free (otf->filename);
   free (otf);
 }