Bug in utoi(), which made it ignore a leading minus sign when
[sgt/halibut] / in_sfnt.c
index f29590b..0d2c7d5 100644 (file)
--- a/in_sfnt.c
+++ b/in_sfnt.c
@@ -506,6 +506,9 @@ static int glyphsbyname_cmp(void const *a, void const *b) {
     glyph gb = cmp_glyphsbyindex[*(unsigned short *)b];
     if (ga < gb) return -1;
     if (ga > gb) return 1;
+    /* For de-duping, we'd prefer to have the first glyph stay first */
+    if (*(unsigned short *)a < *(unsigned short *)b) return -1;
+    if (*(unsigned short *)a > *(unsigned short *)b) return 1;
     return 0;
 }
 static int glyphsbyname_cmp_search(void const *a, void const *b) {
@@ -536,8 +539,8 @@ static void sfnt_mapglyphs(font_info *fi) {
     void *ptr, *end;
     unsigned char *sptr;
     char tmp[256];
-    glyph *extraglyphs;
-    unsigned nextras, i, g;
+    glyph *extraglyphs, prev, this;
+    unsigned nextras, i, g, suflen;
 
     sf->glyphsbyname = sf->glyphsbyindex = NULL;
     if (sfnt_findtable(sf, TAG_post, &ptr, &end)) {
@@ -617,6 +620,42 @@ static void sfnt_mapglyphs(font_info *fi) {
     cmp_glyphsbyindex = sf->glyphsbyindex;
     qsort(sf->glyphsbyname, sf->nglyphs, sizeof(*sf->glyphsbyname),
          glyphsbyname_cmp);
+    /*
+     * It's possible for fonts to specify the same name for multiple
+     * glyphs, which would make one of them inaccessible.  Check for
+     * that, and rename all but one of each set.
+     *
+     * To ensure that we don't clash with any existing glyph names,
+     * our renaming involves appending the glyph number formatted with
+     * enough leading zeroes to make it longer than any all-digit
+     * suffix that already exists in the font.
+     */
+    suflen = 4;
+    for (i = 0; i < sf->nglyphs; i++) {
+       char const *p;
+       p = strrchr(glyph_extern(sfnt_indextoglyph(sf, i)), '.');
+       if (p && !(p+1)[strspn(p+1, "0123456789")] && strlen(p+1) > suflen)
+           suflen = strlen(p+1);
+    }
+    suflen++;
+    prev = sfnt_indextoglyph(sf, sf->glyphsbyname[0]);
+    for (i = 1; i < sf->nglyphs; i++) {
+       if (prev == (this = sfnt_indextoglyph(sf, sf->glyphsbyname[i]))) {
+           char const *basename;
+           char *buf;
+           basename = glyph_extern(this);
+           buf = snewn(strlen(basename) + 2 + suflen, char);
+           strcpy(buf, basename);
+           sprintf(buf + strlen(basename), ".%0*hu", suflen,
+                   sf->glyphsbyname[i]);
+           sf->glyphsbyindex[sf->glyphsbyname[i]] = glyph_intern(buf);
+           sfree(buf);
+       }
+       prev = this;
+    }
+    /* We may have renamed some glyphs, so re-sort the array. */
+    qsort(sf->glyphsbyname, sf->nglyphs, sizeof(*sf->glyphsbyname),
+         glyphsbyname_cmp);
 }
 
 glyph sfnt_indextoglyph(sfnt *sf, unsigned idx) {
@@ -781,9 +820,10 @@ static void sfnt_getkern(font_info *fi) {
 /*
  * Get mapping data from 'cmap' table
  *
- * We look for either a (0, 3), or (3, 1) table, both of these being
- * versions of UCS-2.  We only handle format 4 of this table, since
- * that seems to be the only one in use.
+ * We look for either a (0, 0), (0, 2), (0, 3), or (3, 1) table, all
+ * of these being versions of UCS-2.  We ignore (0, 1), since it's
+ * Unicode 1.1 with precomposed Hangul syllables.  We only handle
+ * format 4 of this table, since that seems to be the only one in use.
  */
 void sfnt_getmap(font_info *fi) {
     sfnt *sf = fi->fontfile;
@@ -809,7 +849,9 @@ void sfnt_getmap(font_info *fi) {
     for (i = 0; i < cmap.numTables; i++) {
        if (!decode(uint16_decode, (char *)base + esd[i].offset, end, &format))
            goto bad;
-       if ((esd[i].platformID == 0 && esd[i].encodingID == 3) ||
+       if ((esd[i].platformID == 0 && esd[i].encodingID == 0) ||
+           (esd[i].platformID == 0 && esd[i].encodingID == 2) ||
+           (esd[i].platformID == 0 && esd[i].encodingID == 3) ||
            (esd[i].platformID == 3 && esd[i].encodingID == 1)) {
            /* UCS-2 encoding */
            if (!decode(uint16_decode, (char *)base + esd[i].offset, end,
@@ -843,17 +885,28 @@ void sfnt_getmap(font_info *fi) {
                        for (k = startCode[j]; k <= endCode[j]; k++) {
                            idx = (k + idDelta[j]) & 0xffff;
                            if (idx != 0) {
-                               if (idx > sf->nglyphs) goto bad;
+                               if (idx > sf->nglyphs)  {
+                                   error(err_sfntbadglyph, &sf->pos, k);
+                                   continue;
+                               }
                                fi->bmp[k] = sfnt_indextoglyph(sf, idx);
                            }
                        }
                    } else {
                        unsigned startidx = idRangeOffset[j]/2 - segcount + j;
                        for (k = startCode[j]; k <= endCode[j]; k++) {
+                           if (startidx + k - startCode[j] >=
+                               nglyphindex) {
+                               error(err_sfntbadglyph, &sf->pos, k);
+                               continue;
+                           }
                            idx = glyphIndexArray[startidx + k - startCode[j]];
                            if (idx != 0) {
                                idx = (idx + idDelta[j]) & 0xffff;
-                               if (idx > sf->nglyphs) goto bad;
+                               if (idx > sf->nglyphs) {
+                                   error(err_sfntbadglyph, &sf->pos, k);
+                                   continue;
+                               }
                                fi->bmp[k] = sfnt_indextoglyph(sf, idx);
                            }
                        }