/*
 * VF_Bdf.c
 *
 *  Programmmed by Hirotsugu Kakugawa, Hiroshima University
 *  E-Mail:  h.kakugawa@computer.org
 *
 *  Edition History
 *   21 Dec 1995  Simple version.
 *   22 Dec 1995  Space & time efficient version.  Added "square" and 
 *                "diamond" dot shapes. Added dot size factor.
 *                Added internal bdf file manager.
 *   26 Dec 1995  Added sorting index if char codes in BDF file are
 *                not arranged in ascending order.
 *   27 Dec 1995  Changed to use index file.
 *   19 Feb 1996  Added "en" and "cs" fontcap entry.
 *    (WL)        Added encoding and character set entry to index file
 *                in the same line as the version number (this is index
 *                version 2).
 *                Added functions to extract char set and encoding data.
 */

/*
 * Use bitmap font in BDF format for X-Window version 11.
 * This font driver also generates outline data from bitmaps.
 * Quality is poor since the source is a bitmap font, but
 * you can get the font files for free!
 * 
 * I tested the following fonts: 
 *     k14.bdf, jiskan16.bdf, jiskan24.bdf
 * This module assumes that all characters in a font file have the
 * same size; variable width fonts are not supported. 
 *                                                      -- H. Kakugawa
 */


/* This file is part of VFlib
 *
 * Copyright (C) 1995-1998 Hirotsugu KAKUGAWA.   All rights reserved.
 *
 * This file is part of the VFlib Library.  This library is free
 * software; you can redistribute it and/or modify it under the terms of
 * the GNU Library General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your
 * option) any later version.  This library 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 Library General Public License for more details.
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */


/*
  Capabilities interpretable by BDF objects:
  "ff"  (str)  --  Font file path  (THIS IS NECESSARY)
  "en"  (str)  --  Font encoding (optional).
                   If defined, encoding must be identical with the value
                   in the bdf index file (which gets the value from the
                   bdf file itself).
  "cs"  (str)  --  Font character set (optional).
                   If defined, character set must be identical with the
                   value in the bdf index file (which gets the value from
                   the bdfindex program).
  "dz"  (num)  --  Dot size factor for each dot. 0(small)...100(full) 
  "ds"  (str)  --  Shape of dots. "square" (default) or "diamond" 
  "ro"  (num)  --  Rotate the char 90*n degrees in clockwise direction
  "rx"  (bool) --  Reflect about x-axis if defined
  "ry"  (bool) --  Reflect about y-axis if defined
  "sl"  (num)  --  Slant the char n/100

  Corrrection Factors:
  "ox"  (num)  --  Offset for x-axis for vector font data (will be subtracted)
  "oy"  (num)  --  Offset for y-axis for vector font data (will be subtracted)
  "fx"  (num)  --  Factor for x-axis for vector font data
  "fy"  (num)  --  Factor for x-axis for vector font data

  Each point p0=(x0,y0) of vector font data is transformed in the 
  following order:
   1. subtraction of `offset' :  (x1,y1)=(x0-x_offset, y0-y_offset)
   2. magnification by `factor': (x2,y2)=(x1*x_factor, y2*y_factor)
   3. computation of the slant
   3. rotation in clockwise direction
   4. reflection about x-axis
   5. reflection about y-axis
 */

#include  <stdio.h> 
#include  <stdlib.h> 
#include  <string.h> 
#include  <ctype.h> 
#include  "config.h"
#include  "defs.h"
#include  "_VF.h"
#include  "VF.h"
#include  "VFcap.h"
#include  "VFenc.h"
#include  "bdf.h"

#ifndef SEEK_SET
#  define SEEK_SET 0
#endif

#define DOT_SHAPE_SQUARE   0
#define DOT_SHAPE_DIAMOND  1

struct s_font {
  int    bdf_id;
  /* capabilities */
  char   *Filename;     /* ff */
  int    Encoding;      /* en */
  int    CharSet;       /* cs */
  int    Rotate;        /* ro */
  int    DotSizeFactor; /* dz */
  int    DotShape;      /* ds */
  int    XReflect;      /* rx */
  int    YReflect;      /* ry */
  int    Slant;         /* sl */
  int    Xoffset;       /* xo */
  int    Yoffset;       /* yo */
  int    Xfactor;       /* xf */
  int    Yfactor;       /* yf */
};
typedef struct s_font  Font;

#define	OL_RANGE	32768
#define	OL_SIZE		8192
#define	OL_OFFSET	((OL_RANGE - OL_SIZE) / 2)

/** DEPENDS ON CHAR CODE (FOR ASCII CODE ONLY) **/  
static int      Xc_To_Dec_Tbl[] = {
  /*0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,  /* 30-3f*/
   -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 40-4f*/
   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 50-5f*/
   -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1}; /* 60-6f*/
#define X_TO_D(c)     ((isxdigit(c))?(Xc_To_Dec_Tbl[c-0x30]):(0))


struct s_ch_table {
  int   ccode;    /* char code */
  long  f_pos;    /* file position */
};
typedef struct s_ch_table  bdf_char_table;

struct s_bdf {
  int            link_count;
  FILE_Port      port;
  int            bdf_enc;
  int            bdf_chset;
  int            bdf_width; 
  int            bdf_height; 
  char           *bdf_filename;
  char           *bdf_idxname;
  unsigned char  *bdf_bmbuf;
  int            bdf_bmrast;
  bdf_char_table *bdf_chars;
  int            bdf_nchar; 
};
typedef struct s_bdf  bdf;

Private bdf  *bdf_table[VF_MAX_BDF_FONTS];

  
Private int    OpenFont();
Private void   Transformation();
Private int    CloseFont();
Private int    GetBitmap();
Private long*  GetOutline();
Private long*  GetOutline2();
Private int    DrawOutline();
Private int    FreeOutline();
Private int    Link();
Private int    Unlink();
Private int    GetEnc();
Private int    GetCharSet();
Private int    ReadCapa();

int            VF_Draw();


Private int    BDF_Open();
Private int    BDF_Close();
Private unsigned char* BDF_ReadBitmap();
Private int    BDF_ReadIndex();
Private long   BDF_GetFilePosition();
Private long   *BDF_GetOutline();


Public FontObj*
CreateFont_Bdf(ent)
  char *ent;
{
  Font    *font;
  FontObj *fobj;

  if ((font = (Font*) malloc(sizeof(Font))) == NULL)
    return NULL;  /* ERR: malloc err */
  if (ReadCapa(font, ent) < 0){
    free(font);
    return NULL;
  }
  fobj = (FontObj*) malloc(sizeof(FontObj));
  fobj->ClassID     = VF_FONT_BDF;
  fobj->Self        = fobj;
  fobj->LinkCount   = 0;
  fobj->OpenFont    = OpenFont;
  fobj->CloseFont   = CloseFont;
  fobj->GetBitmap   = GetBitmap;
  fobj->GetOutline  = GetOutline;
  fobj->GetOutline2 = GetOutline2;
  fobj->DrawOutline = DrawOutline;
  fobj->FreeOutline = FreeOutline;
  fobj->Link        = Link;
  fobj->Unlink      = Unlink;
  fobj->GetEnc      = GetEnc;
  fobj->GetCharSet  = GetCharSet;
  fobj->Locals      = (long) font;
  return fobj;
}
       

Private int
OpenFont(obj)
  FontObj *obj;
{
  int  id;
  Font *fobj;

  fobj = (Font*) obj->Locals;
  if ((id = BDF_Open(fobj->Filename)) < 0)
    return -1;

  /* check whether encoding and character set values in vfontcap are the
     same as the values in the index file */
  if (fobj->Encoding == 0)
    fobj->Encoding = bdf_table[id]->bdf_enc;
  else if (fobj->Encoding != bdf_table[id]->bdf_enc)
    return -1; /* ERR: encoding mismatch */
  if (fobj->CharSet == 0)
    fobj->CharSet = bdf_table[id]->bdf_chset;
  else if (fobj->CharSet != bdf_table[id]->bdf_chset)
    return -1; /* ERR: character set mismatch */

  fobj->bdf_id = id;
  return 0;
}

Private int
CloseFont(obj, fid)
  FontObj  *obj;
  int      fid;
{
  int  id;
  Font *fobj;

  fobj = (Font*) obj->Locals;
  if ((id = BDF_Close(fobj->bdf_id)) < 0)
    return -1;
  return 0;
}

Private int
GetBitmap(obj, CJKcode, w, h, bw, bo, bm_buf)
  FontObj  *obj;
  int   CJKcode;
  int   w;
  int   h;
  int   bw;
  int   bo;
  char  *bm_buf;
{
  int  val;
  long *vfdata;

  if ((vfdata = GetOutline(obj, CJKcode)) == NULL)
    return -1;
  val = DrawOutline(obj, vfdata, w, h, bw, bo, bm_buf);
  FreeOutline(obj, vfdata);
  return val;
}

Private long*
GetOutline(obj, CJKcode)
  FontObj  *obj;
  int      CJKcode;
{
  long  *outline;
  Font  *fobj;
  
  fobj = (Font*) obj->Locals;
  if ((outline = BDF_GetOutline(fobj, fobj->bdf_id, CJKcode)) == NULL)
    return NULL;
  Transformation(&outline[2], fobj);
  return outline;
}

Private long*
GetOutline2(obj, CJKcode)
  FontObj  *obj;
  int      CJKcode;
{
  return GetOutline(obj, CJKcode);
}

Private void
Transformation(vfdata, fobj)
  long *vfdata;
  Font *fobj;
{
  double  t1, t2, t3, t4, t5, t6, sl;
  double tmp_x, tmp_y, xfact, yfact;
  int     x, y, x2, y2, xoffset, yoffset;
  long    *vfp;

  if (vfdata == NULL){
    fprintf(stderr, "NULL OUTLINE DATA [in Transformation() / VF_Bdf.c]\n");
    abort();
  }

  /* Slant */
  sl = fobj->Slant/100.0; 
  if (sl < 0.0){
    t1 = 1.0+sl; t2 = -sl; t3 =0.0; t4 = 0.0; t5 = 1.0; t6 = 0.0; 
  } else {
    t1 = 1.0-sl; t2 = -sl; t3 = sl; t4 = 0.0; t5 = 1.0; t6 = 0.0; 
  }
  xfact = (double)(fobj->Xfactor)/100.0;
  yfact = (double)(fobj->Yfactor)/100.0;
  xoffset = OL_OFFSET + fobj->Xoffset;
  yoffset = OL_OFFSET + fobj->Yoffset;
  
  for (vfp = vfdata; *vfp != (long)0; vfp++){
    if ((*vfp & VFD_TOKEN) == (long)0){
      tmp_x = xfact * (double)(VFD_GET_X(*vfp) - xoffset);
      tmp_y = yfact * (double)(VFD_GET_Y(*vfp) - yoffset);
      
      /* slant */
      x = (int)(t1 * tmp_x + t2 * tmp_y + t3 * OL_SIZE);
      y = (int)(t4 * tmp_x + t5 * tmp_y + t6 * OL_SIZE);
      /* rotate */
      switch (fobj->Rotate % 4){
      default:
      case 0:  x2 = x;          y2 = y;          break;
      case 1:  x2 = OL_SIZE-y;  y2 = x;          break;
      case 2:  x2 = OL_SIZE-x;  y2 = OL_SIZE-y;  break;
      case 3:  x2 = y;          y2 = OL_SIZE-x;  break;
      }
      if (x2 < 0)        x2 = 0;
      if (x2 >= OL_SIZE) x2 = OL_SIZE;
      if (y2 < 0)        y2 = 0;
      if (y2 >= OL_SIZE) y2 = OL_SIZE;
      x2 += OL_OFFSET;   y2 += OL_OFFSET;
      /* reflect x, y */
      if (fobj->XReflect == 1) 
	x2 = OL_RANGE - x2;
      if (fobj->YReflect == 1) 
	y2 = OL_RANGE - y2;
      *vfp = VFD_MAKE_XY(x2, y2);
    }
  }
}

Private int
DrawOutline(obj, vfdata, w, h, bw, bo, bm_buf) 
  FontObj  *obj;
  long     *vfdata;
  int   w;
  int   h;
  int   bw;
  int   bo;
  char  *bm_buf;
{
  unsigned char *buff, d;
  int           rast, x, y, yy1, yy2, val;
  
  rast = (w+7)/8;
  if ((buff = (unsigned char*) malloc(h*rast)) == NULL)
    return -1;   /* ERR: malloc err */ 
  bzero(buff, rast*h);
  if ((val = VF_Draw(vfdata, w, h, rast, buff, 0, 0)) < 0){
    free(buff);
    return -1;
  }    
  yy1 = 0;  yy2 = 0;
  for (y = 0; y < h; y++){
    for (x = 0; x < rast; x++){
      d = buff[yy2 + x];
      bm_buf[yy1 + x]   |= d >> bo;
      bm_buf[yy1 + x+1] |= d << (8-bo);
    }
    yy1 += bw;
    yy2 += rast;
  }
  free(buff);
  return val;
}

Private int
FreeOutline(obj, vfdata)
  FontObj  *obj;
  long*    vfdata;
{
  if (vfdata != NULL)
    free(vfdata);
  return 0;
}


Private int
Link(obj)
  FontObj  *obj;
{
  obj->LinkCount = obj->LinkCount + 1;
  return obj->LinkCount;
}


Private int
Unlink(obj)
  FontObj  *obj;
{
  obj->LinkCount = obj->LinkCount - 1;
  return obj->LinkCount;
}


Private int
GetEnc(obj)
  FontObj  *obj;
{
  Font  *fobj;

  fobj = (Font*) obj->Locals;
  return fobj->Encoding;
}


Private int
GetCharSet(obj)
  FontObj  *obj;
{
  Font  *fobj;

  fobj = (Font*) obj->Locals;
  return fobj->CharSet;
}


static int
ReadCapa(font, ent)
  Font *font;
  char *ent;
{
  char *p;

  font->Encoding      = 0;
  font->CharSet       = 0;
  font->DotSizeFactor = 100;
  font->DotShape      = DOT_SHAPE_SQUARE;
  font->Slant    = 0;
  font->Rotate   = 0;
  font->XReflect = 0;
  font->YReflect = 0;
  font->Xoffset  = 0;
  font->Yoffset  = 0;
  font->Xfactor  = 100;
  font->Yfactor  = 100; 

  VFC_GetEntry(ent);
  /* encoding and character set values will be checked with values from
     index file in OpenFont() */
  if ((p = VFC_GetString(VFCE_ENCODING)) != NULL)
    if ((font->Encoding = VFE_SearchEncoding(p)) < 0)
      return -1;  /* ERR: unknown encoding */
  if ((p = VFC_GetString(VFCE_CHARSET)) != NULL)
    if ((font->CharSet = VFE_SearchCharSet(p)) < 0)
      return -1;  /* ERR: unknown character set */
  if ((font->DotSizeFactor = VFC_GetNumber(VFCE_DOTSIZEFACT)) == -1)
    font->DotSizeFactor = 100;
  if (font->DotSizeFactor < 0)
    font->DotSizeFactor = 0;
  if ((p = VFC_GetString(VFCE_DOTSHAPE)) == NULL)
    font->DotShape = DOT_SHAPE_SQUARE;
  else {
    if (strcmp(p, "diamond") == 0){
      font->DotShape = DOT_SHAPE_DIAMOND;
    } else {
      font->DotShape = DOT_SHAPE_SQUARE;
    }
  }
  if ((font->Slant = VFC_GetNumber(VFCE_SLANT)) == -1)
    font->Slant = 0;
  if ((font->Rotate = VFC_GetNumber(VFCE_ROTATE)) == -1)
    font->Rotate = 0;
  if (VFC_IsDefined(VFCE_REF_X))
    font->XReflect = 1;
  if (VFC_IsDefined(VFCE_REF_Y))
    font->YReflect = 1;
  if ((font->Xoffset = VFC_GetNumber(VFCE_XOFFSET)) == -1)
    font->Xoffset = 0;
  if ((font->Yoffset = VFC_GetNumber(VFCE_YOFFSET)) == -1)
    font->Yoffset = 0;
  if ((font->Xfactor = VFC_GetNumber(VFCE_XFACTOR)) == -1)
    font->Xfactor = 100;
  if ((font->Yfactor = VFC_GetNumber(VFCE_YFACTOR)) == -1)
    font->Yfactor = 100;
  if ((p = VFC_GetString(VFCE_FONT_FILE)) == NULL)
    return -1;
  if ((font->Filename = malloc(strlen(p)+1)) == NULL)
    return -1;  /* ERR: malloc err */
  strcpy(font->Filename, p);

  return 0;
}


/*-- BDF INTERFACE -----------------*/

Private int
BDF_Open(fname)
     char *fname;
{
  int         bdf_id;
  FILE        *fp;
  FILE_Port   idxport;
  static int  inited = 0;

  if (inited == 0){
    /* initialize the table */
    for (bdf_id = 0; bdf_id < VF_MAX_BDF_FONTS; bdf_id++)
      bdf_table[bdf_id] = NULL;
    inited = 1;
  }

  /* Check if the same BDF file is opened */
  for (bdf_id = 0; bdf_id < VF_MAX_BDF_FONTS; bdf_id++){
    if (bdf_table[bdf_id] == NULL)
      continue;
    if (strcmp(fname, bdf_table[bdf_id]->bdf_filename) == 0){
      bdf_table[bdf_id]->link_count++;
      /*printf("FOUND\n");*/
      return bdf_id;
    }
  }
  /* Find a free slot */
  for (bdf_id = 0; bdf_id < VF_MAX_BDF_FONTS; bdf_id++){
    if (bdf_table[bdf_id] == NULL)
      break;
  }
  if (bdf_id == VF_MAX_BDF_FONTS)
    return -1;    /* no free slots */

  /* Allocate BDF structure and initialize it */
  /*printf("OPEN %d (%s)\n", bdf_id, fname);*/
  if ((bdf_table[bdf_id] = (bdf*)malloc(sizeof(bdf))) == NULL)
    return -1;
  bdf_table[bdf_id]->link_count = 1; 
  bdf_table[bdf_id]->bdf_nchar  = -1;
  bdf_table[bdf_id]->bdf_width  = 0; 
  bdf_table[bdf_id]->bdf_height = 0;
  bdf_table[bdf_id]->bdf_filename = malloc(strlen(fname)+strlen(BDF_SUFFIX)+1);
  if (bdf_table[bdf_id]->bdf_filename == NULL)
    goto Err4;
  strcpy(bdf_table[bdf_id]->bdf_filename, fname);
  strcat(bdf_table[bdf_id]->bdf_filename, BDF_SUFFIX);
  bdf_table[bdf_id]->bdf_idxname = malloc(strlen(fname)+strlen(IDX_SUFFIX)+1);
  if (bdf_table[bdf_id]->bdf_idxname == NULL)
    goto Err3;
  strcpy(bdf_table[bdf_id]->bdf_idxname, fname);
  strcat(bdf_table[bdf_id]->bdf_idxname, IDX_SUFFIX);

  /* Read Index file */
  idxport = VFFM_Intern(bdf_table[bdf_id]->bdf_idxname, NULL, NULL);
  if (idxport == NULL_PORT) 
    goto Err2;
  fp = VFFM_FStream(idxport);
  if (BDF_ReadIndex(bdf_id, fp) < 0)
    goto Err1;
  VFFM_UnIntern(idxport);

  /* Allocate bitmap buffer */
  bdf_table[bdf_id]->bdf_bmrast 
    = (bdf_table[bdf_id]->bdf_width+3)/4;
  bdf_table[bdf_id]->bdf_bmbuf 
    = (unsigned char *)calloc(bdf_table[bdf_id]->bdf_height, 
			      bdf_table[bdf_id]->bdf_bmrast);
  if (bdf_table[bdf_id]->bdf_bmbuf == NULL)
    goto Err1;

  /* Intern BDF file */
  bdf_table[bdf_id]->port = 
    VFFM_Intern(bdf_table[bdf_id]->bdf_filename, NULL, NULL);
  if (bdf_table[bdf_id]->port == NULL_PORT) 
    goto Err0;

  return bdf_id;

Err0:
  free(bdf_table[bdf_id]->bdf_bmbuf);
Err1:
  VFFM_UnIntern(idxport);
Err2:
  free(bdf_table[bdf_id]->bdf_idxname);
Err3:
  free(bdf_table[bdf_id]->bdf_filename);
Err4:
  free(bdf_table[bdf_id]);
  bdf_table[bdf_id] = NULL;
  return -1;
}

Private int
BDF_Close(bdf_id)
     int  bdf_id;
{
  if (bdf_table[bdf_id] == NULL){
    printf("VFLIB: BDF - ILLEGAL TO CLOSE\n");
    return -1;
  }
  /* Decrement the link count */
  --bdf_table[bdf_id]->link_count;
  if (bdf_table[bdf_id]->link_count == 0){
    /* release it since the slot is no longer used. */
    VFFM_UnIntern(bdf_table[bdf_id]->port);
    free(bdf_table[bdf_id]->bdf_filename);
    free(bdf_table[bdf_id]->bdf_chars);
    free(bdf_table[bdf_id]);
    bdf_table[bdf_id] = NULL;
  }
  return 0;
}

Private int 
BDF_ReadIndex(bdf_id, fp)
     int bdf_id;
     FILE *fp;
{
  int    chrindex;
  int    version;
  char   buf[160];

  if (bdf_table[bdf_id] == NULL){
    printf("VFLIB: BDF_ReadProp - ILL ARG\n");
    return -1;
  }

  /* read version, character set, and encoding */
  if (fgets(buf, sizeof(buf), fp) == NULL)
    return -1; 
  sscanf(buf, "%d %d %d", &version,
         &bdf_table[bdf_id]->bdf_chset, &bdf_table[bdf_id]->bdf_enc);
  if (version == 1){
    bdf_table[bdf_id]->bdf_chset = CS_JISX0208_1983;  /* default values */
    bdf_table[bdf_id]->bdf_enc = ENC_EUC;
  }
  /* read width/height */
  if (fgets(buf, sizeof(buf), fp) == NULL)
    return -1; 
  sscanf(buf, "%d %d", 
	 &bdf_table[bdf_id]->bdf_width, &bdf_table[bdf_id]->bdf_height);
  /* read #chars */
  if (fgets(buf, sizeof(buf), fp) == NULL)
    return -1; 
  sscanf(buf, "%d", &bdf_table[bdf_id]->bdf_nchar);
  bdf_table[bdf_id]->bdf_chars  = 
    (bdf_char_table*) calloc(bdf_table[bdf_id]->bdf_nchar, 
			     sizeof(bdf_char_table));
  if (bdf_table[bdf_id]->bdf_chars == NULL)
    return -1;
  
  for (chrindex= 0; chrindex < bdf_table[bdf_id]->bdf_nchar; chrindex++){
    if (fgets(buf, sizeof(buf), fp) == NULL)
      break;
    sscanf(buf, "%x %lx", 
	   &bdf_table[bdf_id]->bdf_chars[chrindex].ccode,
	   &bdf_table[bdf_id]->bdf_chars[chrindex].f_pos);
  }
  return 0; 
}

Private unsigned char*
BDF_ReadBitmap(bdf_id, code)
     int bdf_id;
     int code;
{
  int            h, x, i, bm_index;
  char           buf[160], encoded_bm[160];
  long           pos;
  unsigned char  ch;
  FILE           *fp;

  /* go to the file position of the char  */
  if ((pos = BDF_GetFilePosition(bdf_id, code)) < 0)
    return NULL;
  fp = VFFM_FStream(bdf_table[bdf_id]->port);
  fseek(fp, pos, SEEK_SET);

  /* read bitmap data from BDF file */
  bm_index = 0;
  for (h = 0; h < bdf_table[bdf_id]->bdf_height; h++){
    if (fgets(buf, sizeof(buf), fp) == NULL)
      return NULL;
    /*printf("---%s", buf);*/   /*XXX*/
    sscanf(buf, "%s", encoded_bm);
    x = bdf_table[bdf_id]->bdf_bmrast*h;
    /*printf("+++");*/ /*XXX*/
    for (i = 0; ; i++){
      ch = encoded_bm[i];
      if (!isxdigit(ch))
	break;
      bdf_table[bdf_id]->bdf_bmbuf[x++] = X_TO_D(ch);    /* 4bits per byte */
      /*printf("%x", bdf_table[bdf_id]->bdf_bmbuf[x-1]);*/  /*XXX*/
    }
    /*printf("\n");*/ /*XXX*/
  }
  return bdf_table[bdf_id]->bdf_bmbuf;
}

Private long
BDF_GetFilePosition(bdf_id, code)
     int  bdf_id;
     long  code;
{
  int   hi, lo, m;

  /* check the range */
  if (bdf_table[bdf_id]->bdf_nchar <= 0)
    return -1;
  if (code < bdf_table[bdf_id]->bdf_chars[0].ccode)
    return -1;
  if (bdf_table[bdf_id]->bdf_chars[bdf_table[bdf_id]->bdf_nchar-1].ccode 
      < code)
    return -1;

  /* now, use binary search */
  lo = 0;
  hi = bdf_table[bdf_id]->bdf_nchar;
  if (lo >= hi)
    return -1;
  while (lo < hi){
    m = (lo+hi)/2;
    /*printf("lo=%d  hi=%d  m=%d\n", lo, hi, m);*/
    if (bdf_table[bdf_id]->bdf_chars[m].ccode < code){
      lo = m+1;
    } else { /* (code < bdf_table[bdf_id]->bdf_chars[m].ccode) */ 
      hi = m;
    }
  }
  if (bdf_table[bdf_id]->bdf_chars[hi].ccode != code)
    return -1L;   /* not found */

  return bdf_table[bdf_id]->bdf_chars[hi].f_pos;
}

Private long*
BDF_GetOutline(fobj, bdf_id, CJKcode)
     Font  *fobj;
     int bdf_id;
     int  CJKcode;
{
  int            x, y, ry, xx, nbits, size, ol_index;
  int            ol_xl, ol_xr, ol_yu, ol_yl, ol_xc, ol_yc;
  int            ol_xl2, ol_xr2, ol_yu2, ol_yl2;
  long           *outline;
  unsigned char  bmch;
  static char    bit_tbl[] = {0x08, 0x04, 0x02, 0x01};
  static int     nbits_tbl[] = {
    0, 1, 1, 2,   /* 0, 1, 2, 3 */
    1, 2, 2, 3,   /* 4, 5, 6, 7 */
    1, 2, 2, 3,   /* 8, 9, A, B */
    2, 3, 3, 4,   /* C, D, E, F */
  };    

  if (BDF_ReadBitmap(bdf_id, CJKcode) == NULL)
    return NULL;

  /* count # of single bits */
  nbits = 0;
  ry = 0;
  for (y = 0; y < bdf_table[bdf_id]->bdf_height; y++){
    for (x = 0; x < bdf_table[bdf_id]->bdf_bmrast; x++){
      nbits += nbits_tbl[bdf_table[bdf_id]->bdf_bmbuf[ry+x]];
    }
    ry += bdf_table[bdf_id]->bdf_bmrast;
  }

  /* allocate outline data area */
  switch (fobj->DotShape){
  case DOT_SHAPE_SQUARE:
  case DOT_SHAPE_DIAMOND:
  default:
    size = 2 + 5*nbits + 1;
    break;
  }
  if ((outline = (long*)malloc(size*sizeof(long))) == NULL)
    return NULL;

  /* make outline data from bitmap */
  ol_index = 0;

  /* header */
  outline[ol_index++] = CJKcode;
  outline[ol_index++] = VF_SONY_COORDINATES;
  /* a set of black squares */
  ry = 0;
  for (y = 0; y < bdf_table[bdf_id]->bdf_height; y++){
    for (x = 0; x < bdf_table[bdf_id]->bdf_bmrast; x++){
      bmch = bdf_table[bdf_id]->bdf_bmbuf[ry+x];
      if (bmch == 0x00)
	continue;
      ol_yu = (y+0)*OL_SIZE/bdf_table[bdf_id]->bdf_width + OL_OFFSET;
      ol_yl = (y+1)*OL_SIZE/bdf_table[bdf_id]->bdf_width + OL_OFFSET - 1;
      ol_yc = (ol_yu+ol_yl)/2;
      ol_yu2 = fobj->DotSizeFactor*(ol_yu-ol_yc)/100+ol_yc;
      ol_yl2 = fobj->DotSizeFactor*(ol_yl-ol_yc)/100+ol_yc;
      for (xx = 0; xx <= 3; xx++){
	/* if ((bit_tbl[xx] & bmch) != 0x00) printf("x");
	 * else printf(" "); */
	if ((bit_tbl[xx] & bmch) != 0x00){
	  ol_xl = (4*x+xx+0)*OL_SIZE/bdf_table[bdf_id]->bdf_width+OL_OFFSET;
	  ol_xr = (4*x+xx+1)*OL_SIZE/bdf_table[bdf_id]->bdf_width+OL_OFFSET-1;
	  ol_xc = (ol_xl+ol_xr)/2;
	  ol_xl2 = fobj->DotSizeFactor*(ol_xl-ol_xc)/100+ol_xc;
	  ol_xr2 = fobj->DotSizeFactor*(ol_xr-ol_xc)/100+ol_xc;
	  if (fobj->DotShape == DOT_SHAPE_SQUARE){
	    outline[ol_index++] = VFD_TOKEN|VFD_CHAR|VFD_CWCURV|VFD_LINE;
	    outline[ol_index++] = VFD_MAKE_XY(ol_xl2, ol_yu2);
	    outline[ol_index++] = VFD_MAKE_XY(ol_xl2, ol_yl2);
	    outline[ol_index++] = VFD_MAKE_XY(ol_xr2, ol_yl2);
	    outline[ol_index++] = VFD_MAKE_XY(ol_xr2, ol_yu2);
	  } else { /* (fobj->DotShape == DOT_SHAPE_DIAMOND) */
	    outline[ol_index++] = VFD_TOKEN|VFD_CHAR|VFD_CWCURV|VFD_LINE;
	    outline[ol_index++] = VFD_MAKE_XY(ol_xl2, ol_yc);
	    outline[ol_index++] = VFD_MAKE_XY(ol_xc,  ol_yl2);
	    outline[ol_index++] = VFD_MAKE_XY(ol_xr2, ol_yc);
	    outline[ol_index++] = VFD_MAKE_XY(ol_xc,  ol_yu2);
	  }
	}
      }
    }
    /*printf("\n");*/
    ry += bdf_table[bdf_id]->bdf_bmrast;
  }
  /* end of outline */
  outline[ol_index] = 0L;

  return outline;
}

/*EOF*/
