/* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.

    Copyright (C) 2002-2021 by Jin-Hwan Cho and Shunsaku Hirata,
    the dvipdfmx project team.
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/

/*
 * TrueType glyf table is sorted by CID and no CIDToGIDMap is used here.
 * GhostScript can't handle CIDToGIDMap correctly.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "system.h"
#include "numbers.h"
#include "mem.h"
#include "error.h"
#include "dpxconf.h"
#include "dpxfile.h"

#include "unicode.h"

#include "pdfobj.h"
/* pseudo unique tag */
#include "pdffont.h"

#ifndef PDF_NAME_LEN_MAX
#  define PDF_NAME_LEN_MAX 255
#endif

/* TrueType */
#include "sfnt.h"
#include "tt_aux.h"
#include "tt_glyf.h"
#include "tt_cmap.h"
#include "tt_table.h"

#include "tt_gsub.h"

/* CID font */
#include "cmap.h"
#include "type0.h"
#include "cid.h"
#include "cidtype2.h"

/*
 * PDF viewer applications use following tables (CIDFontType 2)
 *
 *  head, hhea, loca, maxp, glyf, hmtx, fpgm, cvt_, prep
 *
 *                                         - from PDF Ref. v.1.3, 2nd ed.
 *
 * The fpgm, cvt_, and prep tables appears only when TrueType instructions
 * requires them. Those tables must be preserved if they exist.
 * We use must_exist flag to indicate `preserve it if present'
 * and to make sure not to cause an error when it does not exist.
 *
 * post and name table must exist in ordinary TrueType font file,
 * but when a TrueType font is converted to CIDFontType 2 font, those tables
 * are no longer required.
 *
 * The OS/2 table (required for TrueType font for Windows and OS/2) contains
 * liscencing information, but PDF viewers seems not using them.
 *
 * The 'name' table added. See comments in ttf.c.
 */

static struct
{
  const char *name;
  int         must_exist;
} required_table[] = {
  {"OS/2", 0}, {"head", 1}, {"hhea", 1}, {"loca", 1}, {"maxp", 1},
  {"name", 1}, {"glyf", 1}, {"hmtx", 1}, {"fpgm", 0}, {"cvt ", 0},
  {"prep", 0}, {NULL, 0}
};

static int
validate_name (char *fontname, int len)
{
  int    i, count;
  char  *p;
  static const char *badstrlist[] = {
    "-WIN-RKSJ-H",
    "-WINP-RKSJ-H",
    "-WING-RKSJ-H",
    "-90pv-RKSJ-H",
    NULL
  };

  for (count = 0, i = 0; i < len; i++) {
    if (fontname[i] == 0) {
      memmove(fontname + i, fontname + i + 1, len - i);
      count++;
      len--;
    }
  }
  if (count > 0) {
    WARN("Removed %d null character(s) from fontname --> %s",
	 count, fontname);
  }
  fontname[len] = '\0';

  /* For some fonts that have bad PS name. ad hoc. remove me. */
  for (i = 0; badstrlist[i] != NULL; i++) {
    p = strstr(fontname, badstrlist[i]);
    if (p && p > fontname) {
      WARN("Removed string \"%s\" from fontname \"%s\".",
	   badstrlist[i], fontname);
      p[0] = '\0';
      len  = (int) (p - fontname);
      break;
    }
  }

  if (len < 1) {
    WARN("No valid character found in fontname string.");
    return -1;
  }

  return 0;
}

/*
 * We will follow the convension for finding ToUnicode CMap described in PDF
 * Reference 4th ed., page 432. The name of "ToCode" (not limited to Unicode
 * here) CMap is obtained by concatenating the registry, ordering, and the
 * name of encoding.
 *
 * UCSms-UCS4, UCSms-UCS2, UCS4 added...
 */

#define WIN_UCS_INDEX_MAX   1
#define KNOWN_ENCODINGS_MAX 10
static struct
{
  unsigned short  platform;
  unsigned short  encoding;
  const char     *pdfnames[5];
} known_encodings[] = {
  {TT_WIN, TT_WIN_UCS4,     {"UCSms-UCS4", "UCSms-UCS2", "UCS4", "UCS2", NULL}},
  {TT_WIN, TT_WIN_UNICODE,  {"UCSms-UCS4", "UCSms-UCS2", "UCS4", "UCS2", NULL}},
  {TT_WIN, TT_WIN_SJIS,     {"90ms-RKSJ", NULL}},
  {TT_WIN, TT_WIN_RPC,      {"GBK-EUC",   NULL}},
  {TT_WIN, TT_WIN_BIG5,     {"ETen-B5",   NULL}},
  {TT_WIN, TT_WIN_WANSUNG,  {"KSCms-UHC", NULL}},
  {TT_MAC, TT_MAC_JAPANESE, {"90pv-RKSJ", NULL}},
  {TT_MAC, TT_MAC_TRADITIONAL_CHINESE, {"B5pc",     NULL}},
  {TT_MAC, TT_MAC_SIMPLIFIED_CHINESE,  {"GBpc-EUC", NULL}},
  {TT_MAC, TT_MAC_KOREAN,   {"KSCpc-EUC", NULL}},
  {0, 4,  {"UCSms-UCS4", "UCSms-UCS2", "UCS4", "UCS2", NULL}},
  {0, 0, {NULL}}
};

static CMap *
find_tocode_cmap (const char *reg, const char *ord, int select)
{
  int   cmap_id = -1, i;
  char *cmap_name;
  const char *append;

  if (!reg || !ord ||
      select < 0 || select > KNOWN_ENCODINGS_MAX) {
    WARN("Character set unknown.");
    return NULL;
  }

  for (i = 0; cmap_id < 0 && i < 5; i++) {
    append = known_encodings[select].pdfnames[i];
    if (!append)
      break;
    cmap_name = NEW(strlen(reg) + strlen(ord) + strlen(append) + 3, char);
    sprintf(cmap_name, "%s-%s-%s", reg, ord, append);
    cmap_id = CMap_cache_find(cmap_name);
    RELEASE(cmap_name);
  }
  if (cmap_id < 0) {
    WARN("Could not find CID-to-Code mapping for \"%s-%s\".", reg, ord);
    WARN("I tried to load (one of) the following file(s):");
    for (i = 0; i < 5; i++) {
      append = known_encodings[select].pdfnames[i];
      if (!append)
	break;
      MESG(" %s-%s-%s", reg, ord, append);
    }
    WARN("Please check if this file exists.");
    return NULL;
  }

  return CMap_cache_get(cmap_id);
}


/*
 * CIDFont glyph metrics:
 * Mostly same as add_CID[HV]Metrics in cidtype0.c.
 */
#define PDFUNIT(v) ((double) (ROUND(1000.0*(v)/(g->emsize), 1)))

static void
add_TTCIDHMetrics (pdf_obj *fontdict, struct tt_glyphs *g,
                   char *used_chars, unsigned char *cidtogidmap, unsigned short last_cid)
{
  int cid, start = 0, prev = 0;
  pdf_obj *w_array, *an_array = NULL;
  double   dw;
  int      empty = 1;

  w_array = pdf_new_array();
  if (g->dw != 0 && g->dw <= g->emsize) {
    dw = PDFUNIT(g->dw);
  } else {
    dw = PDFUNIT(g->gd[0].advw);
  }
  for (cid = 0; cid <= last_cid; cid++) {
    USHORT idx, gid;
    double width;

    if (!is_used_char2(used_chars, cid))
      continue;
    gid = (cidtogidmap) ? ((cidtogidmap[2*cid] << 8)|cidtogidmap[2*cid+1]) : cid;
    idx = tt_get_index(g, gid);
    if (cid != 0 && idx == 0)
      continue;
    width = PDFUNIT((g->gd)[idx].advw);
    if (width == dw) {
      if (an_array) {
        pdf_add_array(w_array, pdf_new_number(start));
        pdf_add_array(w_array, an_array);
        an_array = NULL;
        empty = 0;
      }
    } else {
      if (cid != prev + 1) {
        if (an_array) {
          pdf_add_array(w_array, pdf_new_number(start));
          pdf_add_array(w_array, an_array);
          an_array = NULL;
          empty = 0;
        }
      }
      if (an_array == NULL) {
        an_array = pdf_new_array();
        start = cid;
      }
      pdf_add_array(an_array, pdf_new_number(width));
      prev = cid;
    }
  }

  if (an_array) {
    pdf_add_array(w_array, pdf_new_number(start));
    pdf_add_array(w_array, an_array);
    empty = 0;
  }

  pdf_add_dict(fontdict, pdf_new_name("DW"), pdf_new_number(dw));
  if (!empty) {
    pdf_add_dict(fontdict, pdf_new_name("W"), pdf_ref_obj(w_array));
  }
  pdf_release_obj(w_array);

  return;
}

static void
add_TTCIDVMetrics (pdf_obj *fontdict, struct tt_glyphs *g,
                   char *used_chars, unsigned short last_cid)
{
  pdf_obj *w2_array, *an_array = NULL;
  int    cid;
#if 0
  int    prev = 0, start = 0;
#endif
  double defaultVertOriginY, defaultAdvanceHeight;
  int    empty = 1;

  defaultVertOriginY   = PDFUNIT(g->default_advh - g->default_tsb);
  defaultAdvanceHeight = PDFUNIT(g->default_advh);

  w2_array = pdf_new_array();
  for (cid = 0; cid <= last_cid; cid++) {
    USHORT idx;
#if 0
    USHORT gid;
#endif
    double vertOriginX, vertOriginY, advanceHeight;

    if (!is_used_char2(used_chars, cid))
      continue;
#if 0
    gid = (cidtogidmap) ? ((cidtogidmap[2*cid] << 8)|cidtogidmap[2*cid+1]) : cid;
#endif
    idx = tt_get_index(g, (USHORT)cid);
    if (cid != 0 && idx == 0)
      continue;
    advanceHeight = PDFUNIT(g->gd[idx].advh);
    vertOriginX   = PDFUNIT(0.5*(g->gd[idx].advw));
    vertOriginY   = PDFUNIT(g->gd[idx].tsb + g->gd[idx].ury);
#if 0
    /*
     * c [w1_1y v_1x v_1y w1_2y v_2x v_2y ...]
     * Not working... Why?
     * Acrobat Reader:
     *  Wrong rendering, interpretation of position vector is wrong.
     * Xpdf and gs: ignores W2?
     */
    if (vertOriginY == defaultVertOriginY &&
	advanceHeight == defaultAdvanceHeight) {
      if (an_array) {
	pdf_add_array(w2_array, pdf_new_number(start));
	pdf_add_array(w2_array, an_array);
	an_array = NULL;
	empty = 0;
      }
    } else {
      if (cid != prev + 1 && an_array) {
	pdf_add_array(w2_array, pdf_new_number(start));
	pdf_add_array(w2_array, an_array);
	an_array = NULL;
	empty = 0;
      }
      if (an_array == NULL) {
	an_array = pdf_new_array();
	start = cid;
      }
      pdf_add_array(an_array, pdf_new_number(-advanceHeight));
      pdf_add_array(an_array, pdf_new_number(vertOriginX));
      pdf_add_array(an_array, pdf_new_number(vertOriginY));
      prev = cid;
    }
#else
    /*
     * c_first c_last w1_y v_x v_y
     * This form may hit Acrobat's implementation limit of array element size,
     * 8192. AFPL GhostScript 8.11 stops with rangecheck error with this.
     * Maybe GS's bug?
     */
    if (vertOriginY != defaultVertOriginY ||
	advanceHeight != defaultAdvanceHeight) {
      pdf_add_array(w2_array, pdf_new_number(cid));
      pdf_add_array(w2_array, pdf_new_number(cid));
      pdf_add_array(w2_array, pdf_new_number(-advanceHeight));
      pdf_add_array(w2_array, pdf_new_number(vertOriginX));
      pdf_add_array(w2_array, pdf_new_number(vertOriginY));
      empty = 0;
    }
#endif
  }

#if 0
  if (an_array) {
    pdf_add_array(w2_array, pdf_new_number(start));
    pdf_add_array(w2_array, an_array);
    empty = 0;
  }
#endif

  if (defaultVertOriginY != 880 || defaultAdvanceHeight != 1000) {
    an_array = pdf_new_array();
    pdf_add_array(an_array, pdf_new_number(defaultVertOriginY));
    pdf_add_array(an_array, pdf_new_number(-defaultAdvanceHeight));
    pdf_add_dict(fontdict, pdf_new_name ("DW2"), an_array);
  }
  if (!empty) {
    pdf_add_dict(fontdict,
		 pdf_new_name("W2"),
		 pdf_ref_obj(w2_array));
  }
  pdf_release_obj(w2_array);

  return;
}

/*
 * The following routine fixes few problems caused by vendor specific
 * Unicode mappings.
 */

#define FIX_CJK_UNIOCDE_SYMBOLS 1

static unsigned short
fix_CJK_symbols (unsigned short code)
{
  unsigned short alt_code;
  static struct
  {
    unsigned short alt1;
    unsigned short alt2;
  } CJK_Uni_symbols[] = {
    /*
     * Microsoft/Apple Unicode mapping difference:
     * They are taken from SJIS-Unicode mapping difference but nearly
     * same thing might be applied to Chinese (e.g., Big5) too.
     */
    {0x2014, 0x2015}, /* EM DASH <-> HORIZONTAL BAR */
    {0x2016, 0x2225}, /* DOUBLE VERTICAL LINE <-> PARALLEL TO */
    {0x203E, 0xFFE3}, /* OVERLINE <-> FULLWIDTH MACRON */
    {0x2026, 0x22EF}, /* HORIZONTAL ELLIPSIS <-> MIDLINE HORIZONTAL ELLIPSIS */
    {0x2212, 0xFF0D}, /* MINUS SIGN <-> FULLWIDTH HYPHEN-MINUS */
    {0x301C, 0xFF5E}, /* WAVE DASH <-> FULLWIDTH TILDE */
    {0xFFE0, 0x00A2}, /* FULLWIDTH CENT SIGN <-> CENT SIGN */
    {0xFFE1, 0x00A3}, /* FULLWIDTH POUND SIGN <-> POUND SIGN */
    {0xFFE2, 0x00AC}, /* FULLWIDTH NOT SIGN <-> NOT SIGN */
    {0xFFFF, 0xFFFF}, /* EOD */
  };
#define NUM_CJK_SYMBOLS (sizeof(CJK_Uni_symbols)/sizeof(CJK_Uni_symbols[0]))
  int i;

  alt_code = code;
  for (i = 0; i < NUM_CJK_SYMBOLS; i++) {
    if (CJK_Uni_symbols[i].alt1 == code) {
      alt_code = CJK_Uni_symbols[i].alt2;
      break;
    } else if (CJK_Uni_symbols[i].alt2 == code) {
      alt_code = CJK_Uni_symbols[i].alt1;
      break;
    }
  }

  return alt_code;
}

static int32_t
cid_to_code (CMap *cmap, CID cid, int unicode_cmap)
{
  unsigned char        inbuf[2], outbuf[32];
  int                  inbytesleft = 2, outbytesleft = 32;
  const unsigned char *p;
  unsigned char       *q;

  if (!cmap)
    return cid;

  inbuf[0] = (cid >> 8) & 0xff;
  inbuf[1] = cid & 0xff;
  p = inbuf; q = outbuf;

  CMap_decode_char(cmap, &p, &inbytesleft, &q, &outbytesleft);

  if (inbytesleft != 0)
    return -1;
  else if (outbytesleft == 31)
    return (int32_t) outbuf[0];
  else if (outbytesleft == 30)
    return (int32_t) (outbuf[0] << 8|outbuf[1]);
  else if (outbytesleft == 28) {
    if (unicode_cmap) {
      /* We assume the output encoding is UTF-16. */
      int32_t              uc;
      const unsigned char *endptr;

      p      = outbuf;
      endptr = p + 4;
      uc = UC_UTF16BE_decode_char(&p, endptr);
      if (p != endptr)
        WARN("CID=%u mapped to non-single Unicode characters...", cid);
      return p == endptr ? uc : -1;
    } else {
      return (outbuf[0] << 24)|(outbuf[1] << 16)|(outbuf[2] << 8)|outbuf[3];
    }
  }

  return -1;
}

static uint16_t
cid_to_gid (CMap *cmap, CID cid)
{
  unsigned char        inbuf[2], outbuf[2];
  int                  inbytesleft = 2, outbytesleft = 2;
  const unsigned char *p;
  unsigned char       *q;

  if (!cmap)
    return cid;

  inbuf[0] = (cid >> 8) & 0xff;
  inbuf[1] = cid & 0xff;
  p = inbuf; q = outbuf;

  CMap_decode_char(cmap, &p, &inbytesleft, &q, &outbytesleft);

  if (inbytesleft != 0 || outbytesleft != 0)
    return 0;

  return (uint16_t) (outbuf[0] << 8|outbuf[1]);
}

/* #define NO_GHOSTSCRIPT_BUG 1 */

int
CIDFont_type2_dofont (pdf_font *font)
{
  pdf_obj          *fontfile;
  sfnt             *sfont;
  char             *h_used_chars, *v_used_chars, *used_chars;
  struct tt_glyphs *glyphs;
  CMap             *cmap = NULL;
  tt_cmap          *ttcmap = NULL;
  ULONG             offset = 0;
  CID               cid, last_cid;
  unsigned char    *cidtogidmap;
  USHORT            num_glyphs;
  enum {
    glyph_ordering,
    via_cid_to_code,
    via_cid_to_gid,
  } maptype = via_cid_to_code;
  int               i, unicode_cmap = 0;
  FILE             *fp = NULL;

  if (!font->reference)
    return 0;

  pdf_add_dict(font->resource,
               pdf_new_name("FontDescriptor"), pdf_ref_obj(font->descriptor));

  if (font->flags & PDF_FONT_FLAG_BASEFONT)
    return 0;

  /*
   * CIDSystemInfo comes here since Supplement can be increased.
   */
  {
    pdf_obj *tmp;

    tmp = pdf_new_dict ();
    pdf_add_dict(tmp,
                 pdf_new_name("Registry"),
                 pdf_new_string(font->cid.csi.registry, strlen(font->cid.csi.registry)));
    pdf_add_dict(tmp,
                 pdf_new_name("Ordering"),
                 pdf_new_string(font->cid.csi.ordering, strlen(font->cid.csi.ordering)));
    pdf_add_dict(tmp,
                 pdf_new_name("Supplement"),
                 pdf_new_number(font->cid.csi.supplement));
    pdf_add_dict(font->resource, pdf_new_name("CIDSystemInfo"), tmp);
  }

  /* Quick exit for non-embedded & fixed-pitch font. */
  if (!font->cid.options.embed &&
      (opt_flags_cidfont & CIDFONT_FORCE_FIXEDPITCH)) {
    pdf_add_dict(font->resource, pdf_new_name("DW"), pdf_new_number(1000.0));
    return 0;
  }

  fp = DPXFOPEN(font->filename, DPX_RES_TYPE_TTFONT);
  if (!fp) {
    fp = DPXFOPEN(font->filename, DPX_RES_TYPE_DFONT);
    if (!fp) {
      WARN("Could not open TTF/dfont file: %s", font->filename);
      return -1;
    }
    sfont = dfont_open(fp, font->index);
  } else {
    sfont = sfnt_open(fp);
  }

  if (!sfont) {
    WARN("Could not open TTF file: %s", font->filename);
    DPXFCLOSE(fp);
    return -1;
  }

  switch (sfont->type) {
  case SFNT_TYPE_TTC:
    offset = ttc_read_offset(sfont, font->index);
    if (offset == 0) {
      WARN("Invalid TTC index in %s.", font->filename);
      sfnt_close(sfont);
      DPXFCLOSE(fp);
      return -1;
    }
    break;
  case SFNT_TYPE_TRUETYPE:
    if (font->index > 0) {
      WARN("Found TrueType font file while expecting TTC file (%s).", font->filename);
      sfnt_close(sfont);
      DPXFCLOSE(fp);
      return -1;
    }
    offset = 0;
    break;
  case SFNT_TYPE_DFONT:
    offset = sfont->offset;
    break;
  default:
    WARN("Not a TrueType/TTC font (%s)?", font->filename);
    sfnt_close(sfont);
    DPXFCLOSE(fp);
    return -1;
    break;
  }

  if (sfnt_read_table_directory(sfont, offset) < 0) {
    WARN("Could not read TrueType table directory (%s).", font->filename);
    sfnt_close(sfont);
    DPXFCLOSE(fp);
    return -1;
  }

  /*
   * Adobe-Identity means font's internal glyph ordering here.
   */
  if (!strcmp(font->cid.csi.registry, "Adobe") &&
      !strcmp(font->cid.csi.ordering, "Identity")) {
    maptype = glyph_ordering;
    ttcmap  = NULL;
    cmap    = NULL;
  } else { 
    if (font->cid.csi.registry && font->cid.csi.ordering) {
      char   *cmap_name;
      size_t  len;
      int     cmap_id;

      len  = strlen(font->cid.csi.registry) + strlen(font->cid.csi.ordering);
      len += strlen(font->fontname);
      len += 3;
      cmap_name = NEW(len+1, char);
      snprintf(cmap_name, len + 1, "%s-%s-%s",
               font->cid.csi.registry, font->cid.csi.ordering, font->fontname);
      cmap_id = CMap_cache_find(cmap_name);
      RELEASE(cmap_name);
      if (cmap_id >= 0) {
        cmap    = CMap_cache_get(cmap_id);
        ttcmap  = NULL;
        maptype = via_cid_to_gid;
      }
    }
    if (maptype != via_cid_to_gid) {
      maptype = via_cid_to_code;
      /*
      * This part contains a bug. It may choose SJIS encoding TrueType cmap
      * table for Adobe-GB1.
      */
      for (i = 0; i <= KNOWN_ENCODINGS_MAX; i++) {
        ttcmap = tt_cmap_read(sfont,
                              known_encodings[i].platform,
                              known_encodings[i].encoding);
        if (ttcmap)
          break;
      }
      if (!ttcmap) {
        WARN("No usable TrueType cmap table found for font \"%s\".", font->filename);
        WARN("CID character collection for this font is set to \"%s-%s\"",
             font->cid.csi.registry, font->cid.csi.ordering);
        WARN("Cannot continue without this...");
        sfnt_close(sfont);
        DPXFCLOSE(fp);
        return -1;
      } else if (i <= WIN_UCS_INDEX_MAX) {
        unicode_cmap = 1;
      } else {
        unicode_cmap = 0;
      }

      if (!strcmp(font->cid.csi.ordering, "UCS") && i <= WIN_UCS_INDEX_MAX) {
        cmap = NULL;
      } else {
        cmap = find_tocode_cmap(font->cid.csi.registry, font->cid.csi.ordering, i);
        if (!cmap) {
          sfnt_close(sfont);
          DPXFCLOSE(fp);
          return -1; 
        }
      }
    }
  }

  glyphs = tt_build_init();

  last_cid   = 0;
  num_glyphs = 1; /* .notdef */
  used_chars = h_used_chars = v_used_chars = NULL;
  {
    int c;

    h_used_chars = font->usedchars;
    v_used_chars = font->cid.usedchars_v;
 
    ASSERT(h_used_chars || v_used_chars);  

    /*
     * Quick check of max CID.
     */
    c = 0;
    for (i = 8191; i >= 0; i--) {
      if (h_used_chars && h_used_chars[i] != 0) {
        last_cid = i * 8 + 7;
        c = h_used_chars[i];
        break;
      }
    }
    for (i = 8191; i >= 0; i--) {
      if (v_used_chars && v_used_chars[i] != 0) {
        if (i * 8 + 7 >= last_cid) {
          c = (i * 8 + 7 > last_cid) ? (v_used_chars[i]) : (c | v_used_chars[i]);
          last_cid = i * 8 + 7;
          break;
        }
      }
    }
    if (last_cid > 0) {
      for (i = 0; i < 8; i++) {
        if ((c >> i) & 1)
          break;
        last_cid--;
      }
    }
    ASSERT(last_cid < 0xFFFFu);
  }

#ifndef NO_GHOSTSCRIPT_BUG
  cidtogidmap = NULL;
#else
  cidtogidmap = NEW((last_cid + 1) * 2, unsigned char);
  memset(cidtogidmap, 0, (last_cid + 1) * 2);
#endif /* !NO_GHOSTSCRIPT_BUG */

  /*
   * Map CIDs to GIDs.
   * Horizontal and vertical used_chars are merged.
   */

  /*
   * Horizontal
   */
  if (h_used_chars) {
    used_chars = h_used_chars;
    for (cid = 1; cid <= last_cid; cid++) {
      int32_t  code;
      uint16_t gid = 0;

      if (!is_used_char2(h_used_chars, cid))
        continue;

      switch (maptype) {
      case glyph_ordering:
        gid  = cid;
        code = cid;
        break;
      case via_cid_to_gid: 
        gid  = cid_to_gid(cmap, cid);
        code = cid;
        break;
      case via_cid_to_code:
        code = cid_to_code(cmap, cid, unicode_cmap);
        if (code < 0) {
          WARN("Unable to map CID to code: CID=%u", cid);
        } else {
          gid  = tt_cmap_lookup(ttcmap, code);
#ifdef FIX_CJK_UNIOCDE_SYMBOLS
          if (gid == 0 && unicode_cmap) {
            int alt_code;
          
            alt_code = fix_CJK_symbols((unsigned short)code);
            if (alt_code != code) {
              gid = tt_cmap_lookup(ttcmap, alt_code);
              if (gid != 0) {
                WARN("Unicode char U+%04x replaced with U+%04x.", code, alt_code);
              }
            }
          }
#endif /* FIX_CJK_UNIOCDE_SYMBOLS */
        }
        break;
      }
      if (gid == 0) {
        if (code >= 0)
          WARN("Glyph missing in font. (CID=%u, code=0x%04x)", cid, code);
      }

      /* TODO: duplicated glyph */
#ifndef NO_GHOSTSCRIPT_BUG
      gid = tt_add_glyph(glyphs, gid, cid);
#else
      gid = tt_add_glyph(glyphs, gid, num_glyphs);
      cidtogidmap[2*cid  ] = gid >> 8;
      cidtogidmap[2*cid+1] = gid & 0xff;
#endif /* !NO_GHOSTSCRIPT_BUG */

      num_glyphs++;
    }
  }

  /*
   * Vertical
   */
  if (v_used_chars) {
    otl_gsub *gsub_list = NULL;

    /*
     * Require `vrt2' or `vert'.
     */
    if (maptype != via_cid_to_code) {
      gsub_list = NULL;
    } else {
      gsub_list = otl_gsub_new();
      if (otl_gsub_add_feat(gsub_list, "*", "*", "vrt2", sfont) < 0) {
        if (otl_gsub_add_feat(gsub_list, "*", "*", "vert", sfont) < 0) {
          WARN("GSUB feature vrt2/vert not found.");
          otl_gsub_release(gsub_list);
          gsub_list = NULL;
        } else {
          otl_gsub_select(gsub_list, "*", "*", "vert");
        }
      } else {
        otl_gsub_select(gsub_list, "*", "*", "vrt2");
      }
    }

    for (cid = 1; cid <= last_cid; cid++) {
      int32_t  code;
      uint16_t gid = 0;

      if (!is_used_char2(v_used_chars, cid))
        continue;

      /* There may be conflict of horizontal and vertical glyphs
       * when font is used with /UCS. However, we simply ignore
       * that...
       */
      if (h_used_chars && is_used_char2(h_used_chars, cid)) {
        continue;
      }

      switch (maptype) {
      case glyph_ordering:
        gid  = cid;
        code = cid;
        break;
      case via_cid_to_gid:
        gid  = cid_to_gid(cmap, cid);
        code = cid;
        break;
      case via_cid_to_code:
        code = cid_to_code(cmap, cid, unicode_cmap);
        if (code < 0) {
          WARN("Unable to map CID to code: CID=%u", cid);
        } else {
          gid  = tt_cmap_lookup(ttcmap, code);
#ifdef FIX_CJK_UNIOCDE_SYMBOLS
          if (gid == 0 && unicode_cmap) {
            int alt_code;
          
            alt_code = fix_CJK_symbols((unsigned short)code);
            if (alt_code != code) {
              gid = tt_cmap_lookup(ttcmap, alt_code);
              if (gid != 0) {
                WARN("Unicode char U+%04x replaced with U+%04x.", code, alt_code);
              }
            }
          }
#endif /* FIX_CJK_UNIOCDE_SYMBOLS */
        }
        break;
      }
      if (gid == 0) {
        if (code >= 0)
          WARN("Glyph missing in font. (CID=%u, code=0x%04x)", cid, code);
      } else if (gsub_list) {
        otl_gsub_apply(gsub_list, &gid);
      }

#ifndef NO_GHOSTSCRIPT_BUG
      gid = tt_add_glyph(glyphs, gid, cid);
#else
      gid = tt_add_glyph(glyphs, gid, num_glyphs);
      cidtogidmap[2*cid  ] = gid >> 8;
      cidtogidmap[2*cid+1] = gid & 0xff;
#endif /* !NO_GHOSTSCRIPT_BUG */

      if (used_chars) /* merge vertical used_chars to horizontal */
        add_to_used_chars2(used_chars, cid);

      num_glyphs++;
    }

    if (gsub_list)
      otl_gsub_release(gsub_list);

    if (!used_chars) /* We have no horizontal. */
      used_chars = v_used_chars;
  }

  ASSERT(used_chars);

  tt_cmap_release(ttcmap);

  if (font->cid.options.embed) {
    if (tt_build_tables(sfont, glyphs) < 0) {
      WARN("Could not created FontFile stream.");
      if (cidtogidmap)
        RELEASE(cidtogidmap);
      sfnt_close(sfont);
      DPXFCLOSE(fp);
      return -1;
    }
    if (dpx_conf.verbose_level > 1)
      MESG("[%u glyphs (Max CID: %u)]", glyphs->num_glyphs, last_cid);
  } else {
    if (tt_get_metrics(sfont, glyphs) < 0) {
      WARN("Reading glyph metrics failed...");
      if (cidtogidmap)
        RELEASE(cidtogidmap);
      sfnt_close(sfont);
      DPXFCLOSE(fp);
      return -1;
    }
  }

  /*
   * DW, W, DW2, and W2
   */
  if (opt_flags_cidfont & CIDFONT_FORCE_FIXEDPITCH) {
    pdf_add_dict(font->resource, pdf_new_name("DW"), pdf_new_number(1000.0));
  } else {
    add_TTCIDHMetrics(font->resource, glyphs, used_chars, cidtogidmap, last_cid);
    if (font->cid.need_vmetrics)
      add_TTCIDVMetrics(font->resource, glyphs, used_chars, last_cid);
  }

  /* CIDSet
   * NOTE: All glyphs including component glyph and dummy glyph must be
   * listed in CIDSet. However, .notdef glyph should be ommitted.
   */
  if (pdf_check_version(2, 0) < 0) {
    pdf_obj *cidset;
    char    *cidset_data;

    cidset_data = NEW(glyphs->last_gid/8 + 1, char);
    memset(cidset_data, 0, glyphs->last_gid/8 + 1);
    for (i = 1; i <= glyphs->last_gid; i++)
      cidset_data[i/8] |= (1 << (7 - i % 8));
    cidset = pdf_new_stream(STREAM_COMPRESS);
    pdf_add_stream(cidset, cidset_data, glyphs->last_gid/8 + 1);
    RELEASE(cidset_data);
    pdf_add_dict(font->descriptor,
      pdf_new_name("CIDSet"), pdf_ref_obj(cidset));
    pdf_release_obj(cidset);
  }

  tt_build_finish(glyphs);

  /* Finish here if not embedded. */
  if (!font->cid.options.embed) {
    if (cidtogidmap)
      RELEASE(cidtogidmap);
    sfnt_close(sfont);
    DPXFCLOSE(fp);

    return 0;
  }

  /* Create font file */
  for (i = 0; required_table[i].name; i++) {
    if (sfnt_require_table(sfont,
			   required_table[i].name,
			   required_table[i].must_exist) < 0) {
      WARN("Some required TrueType table (%s) does not exist.", required_table[i].name);
      if (cidtogidmap)
        RELEASE(cidtogidmap);
      sfnt_close(sfont);
      DPXFCLOSE(fp);
      return -1;
    }
  }

  /*
   * FontFile2
   */
  fontfile = sfnt_create_FontFile_stream(sfont);

  sfnt_close(sfont);
  DPXFCLOSE(fp);

  if (!fontfile) {
    WARN("Could not created FontFile stream for \"%s\".", font->filename);
    if (cidtogidmap)
      RELEASE(cidtogidmap);
    return -1;
  }
  if (dpx_conf.verbose_level > 1) {
    MESG("[%ld bytes]", pdf_stream_length(fontfile));
  }

  pdf_add_dict(font->descriptor, pdf_new_name("FontFile2"), pdf_ref_obj (fontfile));
  pdf_release_obj(fontfile);

  /*
   * CIDToGIDMap
   * Adobe's PDF Reference had been describing it as "optional" and
   * default value as "Identity". However, ISO 32000-1 requires it
   * for Type 2 CIDFonts with embedded font programs.
   */
  if (!cidtogidmap) {
    pdf_add_dict(font->resource, pdf_new_name("CIDToGIDMap"), pdf_new_name("Identity"));
  } else {
    pdf_obj *c2gmstream;

    c2gmstream = pdf_new_stream(STREAM_COMPRESS);
    pdf_add_stream(c2gmstream, cidtogidmap, (last_cid + 1) * 2);
    pdf_add_dict(font->resource, pdf_new_name("CIDToGIDMap"), pdf_ref_obj (c2gmstream));
    pdf_release_obj(c2gmstream);
    RELEASE(cidtogidmap);
  }
  
  return 0;
}

int
CIDFont_type2_open (pdf_font *font, const char *name, int index, cid_opt *opt)
{
  int      error;
  char    *fontname;
  sfnt    *sfont;
  ULONG    offset = 0;
  FILE    *fp     = NULL;

  ASSERT(font && opt);

  fp = DPXFOPEN(name, DPX_RES_TYPE_TTFONT);
  if (!fp) {
    fp = DPXFOPEN(name, DPX_RES_TYPE_DFONT);
    if (!fp) return -1;
    sfont = dfont_open(fp, index);
  } else {
    sfont = sfnt_open(fp);
  }

  if (!sfont) {
    DPXFCLOSE(fp);
    return -1;
  }

  switch (sfont->type) {
  case SFNT_TYPE_TTC:
    offset = ttc_read_offset(sfont, index);
    break;
  case SFNT_TYPE_TRUETYPE:
    if (index > 0) {
      WARN("Invalid TTC index (not TTC font): %s", name);
      sfnt_close(sfont);
      DPXFCLOSE(fp);
      return -1;
    }
    offset = 0;
    break;
  case SFNT_TYPE_DFONT:
    offset = sfont->offset;
    break;
  default:
    sfnt_close(sfont);
    DPXFCLOSE(fp);
    return -1;
  }

  if (sfnt_read_table_directory(sfont, offset) < 0) {
    WARN("Reading TrueType table directory failed: %s", name);
    sfnt_close(sfont);
    DPXFCLOSE(fp);
    return -1;
  }

  /* Ignore TrueType Collection with CFF table. */
  if (sfont->type == SFNT_TYPE_TTC && sfnt_find_table_pos(sfont, "CFF ")) {
    sfnt_close(sfont);
    DPXFCLOSE(fp);
    return -1;
  }

  {
    char *shortname;
    int   namelen;

    /* MAC-ROMAN-EN-POSTSCRIPT or WIN-UNICODE-EN(US)-POSTSCRIPT */
    shortname = NEW(PDF_NAME_LEN_MAX, char);
    namelen   = tt_get_ps_fontname(sfont, shortname, PDF_NAME_LEN_MAX);
    if (namelen == 0) {
      memset(shortname, 0, PDF_NAME_LEN_MAX);
      strncpy(shortname, name, PDF_NAME_LEN_MAX);
      namelen = strlen(shortname);
    }
    error = validate_name(shortname, namelen); /* for SJIS, UTF-16, ... string */
    if (error) {
      RELEASE(shortname);
      sfnt_close(sfont);
      DPXFCLOSE(fp);
      return -1;
    } 
    /*
     * Strlen works, after validate_named string.
     * Mangled name requires more 7 bytes.
     * Style requires more 11 bytes.
     */
    fontname = NEW(strlen(shortname)+19, char);
    strcpy(fontname, shortname);
    RELEASE(shortname);
  }

  if (opt->embed && opt->style != FONT_STYLE_NONE) {
    WARN("Embedding disabled due to style option for %s.", name);
    opt->embed = 0;
  }
  switch (opt->style) {
  case FONT_STYLE_BOLD:
    strcat(fontname, ",Bold");
    break;
  case FONT_STYLE_ITALIC:
    strcat(fontname, ",Italic");
    break;
  case FONT_STYLE_BOLDITALIC:
    strcat(fontname, ",BoldItalic");
    break;
  }
  /*
   * CIDSystemInfo is determined from CMap or from map record option.
   */
  font->fontname = fontname;
  font->subtype  = PDF_FONT_FONTTYPE_CIDTYPE2;
  if (opt->csi.registry && opt->csi.ordering) {
    font->cid.csi.registry   = NEW(strlen(opt->csi.registry)+1, char);
    strcpy(font->cid.csi.registry, opt->csi.registry);
    font->cid.csi.ordering   = NEW(strlen(opt->csi.ordering)+1, char);
    strcpy(font->cid.csi.ordering, opt->csi.ordering);
    font->cid.csi.supplement = opt->csi.supplement;
  }

  font->resource = pdf_new_dict();
  pdf_add_dict(font->resource, pdf_new_name("Type"), pdf_new_name("Font"));
  pdf_add_dict(font->resource, pdf_new_name("Subtype"), pdf_new_name("CIDFontType2"));

  font->descriptor = tt_get_fontdesc(sfont, &(opt->embed), opt->stemv, 0, name);
  if (!font->descriptor) {
    WARN("Could not obtain necessary font info: %s", name);
    sfnt_close(sfont);
    DPXFCLOSE(fp);
    return -1;
  }

  if (opt->embed) {
    char *tmp;
    
    pdf_font_make_uniqueTag(font->uniqueID);
    tmp = NEW(strlen(fontname)+8, char);
    sprintf(tmp, "%s+%s", font->uniqueID, font->fontname);
    pdf_add_dict(font->descriptor, pdf_new_name("FontName"), pdf_new_name(tmp));
    pdf_add_dict(font->resource,   pdf_new_name("BaseFont"), pdf_new_name(tmp));
    RELEASE(tmp);
  } else {
    pdf_add_dict(font->descriptor, pdf_new_name("FontName"), pdf_new_name(font->fontname));
    pdf_add_dict(font->resource,   pdf_new_name("BaseFont"), pdf_new_name(font->fontname));
  }

  sfnt_close(sfont);
  if (fp)
    DPXFCLOSE(fp);

  /*
   * Don't write fontdict here.
   * /Supplement in /CIDSystemInfo may change.
   */

  return 0;
}
