/*
 * VF_Jg.c
 *
 *  Originally Programmmed by Hideo "Sir MaNMOS" Morisita
 *  New implementation by Hirotsugu Kakugawa
 *  E-Mail:  h.kakugawa@computer.org
 *
 *  Edition History
 *  10 Nov 1993
 *  20 Nov 1993  Debugged
 *  21 Nov 1993  ro, sl, ox, oy, fx, fy implemented
 *  20 Jan 1994  Added GetOutline2().
 *   8 Mar 1994  Implemented Sony compatible outline extraction routine
 *   8 Mar 1994  Fixed small bugs and removed dead code
 *  11 Mar 1994  Changed draw routine
 *   3 Sep 1994  Changed type declaration of ConvXY() 
 *   3 Feb 1995  Bug fix for left slant conversion.
 *  16 Mar 1995  Changed header reading routine not to read 
 *               everything at initialization.
 *  16 Mar 1995  Fixed memory leak in JGOpenFont().
 *   6 May 1995  Dynamic Opening/Closing font file feature by H.Kakugawa.
 *  23 May 1995  Added range checking of char code.
 *  21 Mar 1996  Added range checking of a point in ReadXY().
 *
 */


/* This file is part of VFlib
 *
 * Copyright (C) 1993-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 jg font objects:
  "ff"  (str)  --  Font file path  (THIS IS NECESSARY)
  "fr"  (bool) --  Frame font if defined
  "th"  (bool) --  Thicken the char if defined
  "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. addition of `offset' :  (x1,y1)=(x0-x_offset, y0-y_offset)
   2. magnification by `factor': (x2,y2)=(x1*x_factor, y2*y_factor)
   3. computing 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  "config.h"
#include  "defs.h"
#include  <fcntl.h> 
#include  "_VF.h"
#include  "VF.h"
#include  "VFcap.h"


#define JG_MAX_VALUE         0x0fff
#define JG_MAX_XY            0x07ff
#define JG_XY_MASK           0x07ff
#define JG_CMD_MASK          0x0800

#define JG_CODE_SIZE0        0x0582
#define JG_CODE_SIZE1        0x0bc0
#define JG_CODE_SIZE2        0x0d96
/*#define JG_CODE_SIZE2        0x0d3d*/


#define STATIC static
#define CONV_X(x)  \
   ((unsigned int)(OUTLINE_OFFSET+((x)*OUTLINE_SIZE)/JG_MAX_XY))
#define CONV_Y(y)  \
   ((unsigned int)(OUTLINE_OFFSET+((y)*OUTLINE_SIZE)/JG_MAX_XY))
#define UNCONV_X(x)  \
   ((unsigned int)(JG_MAX_XY*((x)-OUTLINE_OFFSET))/OUTLINE_SIZE)
#define UNCONV_Y(y)  \
   ((unsigned int)(JG_MAX_XY*((y)-OUTLINE_OFFSET))/OUTLINE_SIZE)

#define EMPTY_PTR  0xffffffff

struct s_font {
  int    PrimFont;
  char   *FontFileName; /* ff */
  int    Frame;         /* fr */
  int    Thicken;       /* th */
  int    Rotate;        /* ro */
  int    XReflect;      /* rx */
  int    YReflect;      /* ry */
  int    Slant;         /* sl */
  int    Xoffset;       /* ox */
  int    Yoffset;       /* oy */
  int    Xfactor;       /* fx */
  int    Yfactor;       /* fy */
  double MatT1, MatT2, MatT3, MatT4, MatT5, MatT6;
};
typedef struct s_font  Font;


Private int    OpenFont();
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 void   ConvXY();

int            VF_Draw();

static int   ReadCapa();
static int   JGOpenFont();
static int   JGCloseFont();
static int   JGReadHeader();
static long* JGReadOutline();

static void          InitBitStream();
static int           ReadXY();
static unsigned long Read4Bytes();
static int           Read1Byte();
static unsigned int  Read12Bits();
static int           CorrectSize();
static void          Seek();
static long          CurrentPos();

Private int   jis2c();



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

  if ((font = (Font*) malloc(sizeof(Font))) == NULL)
    return NULL;  /* ERR: malloc err */
  font->PrimFont = -1;
  if (ReadCapa(font, ent) < 0){
    free(font);
    return NULL;
  }
  
  fobj = (FontObj*) malloc(sizeof(FontObj));
  if (fobj == NULL){
    free(font->FontFileName); 
    free(font);
    return NULL;
  }
  fobj->ClassID     = VF_FONT_JG;
  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->GetCharSet  = NULL;
  fobj->GetEnc      = NULL;
  fobj->Link        = Link;
  fobj->Unlink      = Unlink;
  fobj->Locals      = (long) font;
  return fobj;
}
       

Private int
OpenFont(obj)
  FontObj* obj;
{
  Font       *font;

  font = (Font*) obj->Locals;
  font->PrimFont = JGOpenFont(font->FontFileName);
  return font->PrimFont;
}


Private int
CloseFont(obj)
  FontObj  *obj;
{
  Font  *font;

  font = (Font*) obj->Locals;
  return JGCloseFont(font->PrimFont);
}

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

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



Private long*
GetOutline(obj, jiscode)
  FontObj  *obj;
  int      jiscode;
{
  Font   *font;
  int    id, x, y;
  long   *outline, *ptr;

  font = (Font*) obj->Locals;
  id   = font->PrimFont;
  if ((outline = JGReadOutline(2, jiscode, id)) == NULL)
    return NULL;
  outline[0] = jiscode;
  outline[1] = VF_SONY_COORDINATES;
  for (ptr = &outline[2]; *ptr != 0L; ptr++){
    if ((*ptr & VFD_TOKEN) == VFD_TOKEN)
      continue;
    ConvXY(&x, &y, VFD_GET_X(*ptr), VFD_GET_Y(*ptr), font);
    *ptr = VFD_MAKE_XY(CONV_X(x), CONV_Y(y));
  }
  return outline;
}



Private long*
GetOutline2(obj, jiscode)
  FontObj  *obj;
  int      jiscode;
{
  Font   *font;
  int    id, x, y;
  long   *outline, *ptr;

  font = (Font*) obj->Locals;
  id = font->PrimFont;
  if ((outline = (long*) JGReadOutline(2, jiscode, id)) == NULL)
    return NULL;
  outline[0] = jiscode;
  outline[1] = VF_JG_COORDINATES;
  for (ptr = &outline[2]; *ptr != 0L; ptr++){
    if ((*ptr & VFD_TOKEN) == VFD_TOKEN)
      continue;
    ConvXY(&x, &y, VFD_GET_X(*ptr), VFD_GET_Y(*ptr), font);
    *ptr = VFD_MAKE_XY(x, y);
  }
  return outline;
}



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;
{
  Font          *font;
  int           x, y, rast, yy1, yy2, val, frame;
  unsigned char *buff, d;
  int           thin;

  font = (Font*) obj->Locals;
  rast = (w+7)/8;
  if ((buff = (unsigned char*) malloc(h*rast)) == NULL)
    return -1; /* ERR: malloc err */ 
  bzero(buff, rast*h);

  switch (font->Thicken){
  case 1:    thin = 30; break;
  case 0: 
  default:   thin =  0; break;
  }
  switch (font->Frame){
  case 1:    frame = 1; break;
  case 0: 
  default:   frame = 0; break;
  }
  val = VF_Draw(vfdata, w, h, rast, buff, thin, frame);
  if (val < 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;
  char  *vfdata;
{
  free((char*) 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
ReadCapa(font, ent)
  Font *font;
  char *ent;
{
  double  sl;
  char    *p;

  font->Thicken  = 0;
  font->Frame    = 0;
  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);

  if (VFC_IsDefined(VFCE_THICKEN))
    font->Thicken = 1;
  if (VFC_IsDefined(VFCE_FRAME))
    font->Frame = 1;
  if ((font->Slant = VFC_GetNumber(VFCE_SLANT)) == -1)
    font->Slant = 0;
  sl = font->Slant/100.0; 
  if (sl < 0.0){
    font->MatT1 = 1.0+sl;  font->MatT2 = -sl;   font->MatT3 = 0.0;
    font->MatT4 = 0.0;     font->MatT5 = 1.0;   font->MatT6 = 0.0; 
  } else {
    font->MatT1 = 1.0-sl;  font->MatT2 = -sl;   font->MatT3 = sl;
    font->MatT4 = 0.0;     font->MatT5 = 1.0;   font->MatT6 = 0.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;

  font->FontFileName = NULL;
  if ((p = VFC_GetString(VFCE_FONT_FILE)) == NULL)
    return -1;
  if ((font->FontFileName = malloc(strlen(p)+1)) == NULL)
    return -1;  /* ERR: malloc err */
  strcpy(font->FontFileName, p);
  return 0;
}



Private void
ConvXY(xp, yp, x, y, fobj)
  int   *xp, *yp, x, y;
  Font  *fobj;
{
  double tmp_x, tmp_y, xfact, yfact;
  int    xx, yy, xxx, yyy;

  xfact = (double)(fobj->Xfactor)/100.0;
  yfact = (double)(fobj->Yfactor)/100.0;
  tmp_x = (double) (xfact*(x-(fobj->Xoffset)));
  tmp_y = (double) (yfact*(y-(fobj->Yoffset)));
  tmp_x = (((double)tmp_x*(fobj->MatT1)) + ((double)tmp_y*(fobj->MatT2)) 
	   + ((double) JG_MAX_XY)*(fobj->MatT3));
  tmp_y = (((double)tmp_x*(fobj->MatT4)) + ((double)tmp_y*(fobj->MatT5))
	   + ((double) JG_MAX_XY)*(fobj->MatT6));
  xxx = (int) tmp_x;
  yyy = (int) tmp_y;
  switch (fobj->Rotate % 4){
  default:
  case 0:
    xx = xxx;                yy = yyy;               break;
  case 1:    
    xx = JG_MAX_XY -1 - yyy; yy = xxx;               break;
  case 2:
    xx = JG_MAX_XY-1 - xxx;  yy = JG_MAX_XY-1 - yyy; break;
  case 3:
    xx = yyy;                yy = JG_MAX_XY-1 - xxx; break;
  }
  if (fobj->XReflect != 0)  xx = JG_MAX_XY-1 - xx;
  if (fobj->YReflect != 0)  yy = JG_MAX_XY-1 - yy;
  if (xx < 0) xx = 0;
  if (yy < 0) yy = 0;
  if (xx >= JG_MAX_XY) xx = JG_MAX_XY-1;
  if (yy >= JG_MAX_XY) yy = JG_MAX_XY-1;
  *xp = xx; 
  *yp = yy;
}




/***
 *** LOW LEVEL INTERFACE ROUTINES TO JG FONTS
 ***   BY HIROTSUGU KAKUGAWA 1994
 ***/

typedef struct {
  int  n; 
  int  base;
  long *Offset;
  long *Size;
} Header;

struct prim_font {
  FILE_Port  Fds[3];
  Header     *Headers[3];
  int        LinkCount;
  char       *FontFileName;   /* ff */
};
typedef struct prim_font  PrimFont;
static PrimFont  PrimFontTable[VF_MAX_JG_FONTS];

#define THRESHOLD_SIZE  0x1000


/* OPEN THE FONT */
STATIC int
JGOpenFont(font)
  char *font;
{
  int     id, i, j;
  char	  *fn;
  static int  inited = 0;
  static char suff[3] = {'0', '1', '2'}; 
  static int  size[3] = {JG_CODE_SIZE0, JG_CODE_SIZE1, JG_CODE_SIZE2};

  if (inited == 0){
    for (id = 0; id < VF_MAX_JG_FONTS; id++){
      for (i = 0; i < 3; i++){
	PrimFontTable[id].Fds[i]          = NULL_PORT;
	PrimFontTable[id].Headers[i]      = NULL;
      }
      PrimFontTable[id].LinkCount       = 0;
      PrimFontTable[id].FontFileName    = NULL;
    }
    inited = 1;
  }

  for (id = 0; id < VF_MAX_JG_FONTS; id++){
    /* linear search is sufficient since # of items is small */
    if ((PrimFontTable[id].Fds[0] != NULL_PORT) &&
	(strcmp(PrimFontTable[id].FontFileName, font) == 0)){
      PrimFontTable[id].LinkCount++;
      return id;
    }
  }

  for (id = 0; id < VF_MAX_JG_FONTS; id++){
    if (PrimFontTable[id].Fds[0] == NULL_PORT)
      break;
  }
  if (id == VF_MAX_JG_FONTS)
    return -1;  /* full */

  if ((PrimFontTable[id].FontFileName = malloc(strlen(font)+1)) == NULL)
    return -1;  /* ERR: malloc err */
  strcpy(PrimFontTable[id].FontFileName, font);

  if ((fn = malloc(strlen(font)+5)) == NULL){
    free(PrimFontTable[id].FontFileName);
    return -1;
  }

  for (i = 0; i < 3; i++){
    PrimFontTable[id].Fds[i]     = NULL_PORT;
    PrimFontTable[id].Headers[i] = NULL;
  }

  for (i = 0; i < 3; i++){
    PrimFontTable[id].Headers[i] = (Header*)malloc(sizeof(Header));
    if (PrimFontTable[id].Headers[i] == NULL)
      goto Error;
    PrimFontTable[id].Headers[i]->Offset = NULL;
    PrimFontTable[id].Headers[i]->Size   = NULL;

    sprintf(fn, "%s.fn%c", font, suff[i]);
    PrimFontTable[id].Fds[i] = VFFM_Intern(fn, NULL, NULL);
    if (PrimFontTable[id].Fds[i] == NULL_PORT)
      goto Error;

    /***printf("  OPEN %s\n", fn);***/
    PrimFontTable[id].Headers[i]->n      = size[i];
    PrimFontTable[id].Headers[i]->base   = 0;
    PrimFontTable[id].Headers[i]->Offset = (long*)malloc(size[i]*sizeof(long));
    if (PrimFontTable[id].Headers[i]->Offset  == NULL)
      goto Error;
    PrimFontTable[id].Headers[i]->Size = (long*)malloc(size[i]*sizeof(long));
    if (PrimFontTable[id].Headers[i]->Size == NULL)
      goto Error;
    if (PrimFontTable[id].Fds[i] != NULL_PORT)
      JGReadHeader(PrimFontTable[id].Fds[i], PrimFontTable[id].Headers[i]);
  }
  free(fn);
  return id;

Error:
  for (j = 0; j < i; j++){
    if (PrimFontTable[id].Fds[j] != NULL_PORT)
      (void) VFFM_UnIntern(PrimFontTable[id].Fds[j]);
    PrimFontTable[id].Fds[j] = NULL_PORT;
  }
  free(PrimFontTable[id].FontFileName);
  free(fn);
  if (PrimFontTable[id].Headers[i] != NULL){
    if (PrimFontTable[id].Headers[i]->Offset != NULL)
      free(PrimFontTable[id].Headers[i]->Offset);
    if (PrimFontTable[id].Headers[i]->Size != NULL)
      free(PrimFontTable[id].Headers[i]->Size);
    free(PrimFontTable[id].Headers[i]);
  }
  return -1;
}


/* CLOSE THE FONT */
STATIC int
JGCloseFont(id)
  int  id;
{
  int  i;

  if ((--PrimFontTable[id].LinkCount) <= 0){
    for (i = 0; i < 3; i++){
      if (PrimFontTable[id].Fds[i] != NULL_PORT)
        (void) VFFM_UnIntern(PrimFontTable[id].Fds[i]);
      PrimFontTable[id].Fds[i] = NULL_PORT;
      free(PrimFontTable[id].Headers[i]->Offset);
      free(PrimFontTable[id].Headers[i]->Size);
      free(PrimFontTable[id].Headers[i]);
    }
    free(PrimFontTable[id].FontFileName);
  }
  return PrimFontTable[id].LinkCount;
}


static int 
JGReadHeader(port, hd)
     FILE_Port  port;
     Header     *hd;
{
  int                  prefix, i, j, CodeSize;
  FILE                 *fp;
  
  fp = VFFM_FStream(port);
  fseek(fp, 8L, 0);
  prefix  = (unsigned int) Read1Byte(fp);
  prefix += (unsigned int) Read1Byte(fp)*0x100;
  /***printf("  PREFIX %04x \n", prefix); ***/
  fseek(fp, (long)(prefix+0x0a), 0);

  hd->base = 10 + prefix + 4*hd->n;
  CodeSize = hd->n;
  for (i = 0; i < CodeSize; i++){
    hd->Offset[i] = Read4Bytes(fp);
    /*printf("  OFFSET %04x  %04x\n", i, hd->Offset[i]);*/
    if (hd->Offset[i] != EMPTY_PTR)
      hd->Offset[i] += hd->base;
  }

  for (i = 0; i < CodeSize-1; i++){
    if (hd->Offset[i] == EMPTY_PTR){
      hd->Size[i] = 0;
    } else {
      /***printf("  OFFSET %04x  %04x\n", i, hd->Offset[i]);***/
      for (j = i+1; ; j++){
	if (j >= CodeSize){
	  hd->Size[i] = -(THRESHOLD_SIZE+1);
	  break;
	}
	if (hd->Offset[j] != EMPTY_PTR){
	  hd->Size[i] = -(hd->Offset[j] - hd->Offset[i]);
	  break;
	}
      }
    }
    /***printf("  SIZE %04x  %04x\n", i, -hd->Size[i]);***/
    if (-(hd->Size[i]) > THRESHOLD_SIZE){
      hd->Size[i] = EMPTY_PTR;
      /* CorrectSize(i, fp, hd);   TOO LARGE. IS THE SIZE CORRECT? */
    }
  }
  /* when i == CodeSize-1: */
  if (hd->Offset[CodeSize-1] == EMPTY_PTR)
    hd->Size[CodeSize-1] = 0;
  else {
    hd->Size[CodeSize-1] = -(THRESHOLD_SIZE+1);
    CorrectSize(CodeSize-1, fp, hd);
  }
  return 0;
}


/* CORRECT THE SIZE OF FONT DATA */
static int
CorrectSize(i, fp, hd) 
  int    i;
  FILE   *fp;
  Header *hd;
{
  int                   x, y;

  /***printf("Too Large for %04x\n   Size:%04x ", i, -(hd->Size[i]));***/
  Seek(fp, hd->Offset[i]);
  InitBitStream(fp);
  for (;;){
    if (ReadXY(fp, &x, &y) == -1)
      break;
    while (ReadXY(fp, &x, &y) != -1)
      ;
  }
  hd->Size[i] = -(CurrentPos(fp) - hd->Offset[i]);
  /***printf("-->  %04x\n", -(hd->Size[i]));***/
  return hd->Size[i];
}


/* GET OUTLINE DATA (IN JG COORDINATES) */
STATIC long*
JGReadOutline(offset, jiscode, id)
     int  offset, jiscode, id;
{
  FILE_Port  port;
  FILE       *fp;
  int    fnt_file;
  int    token_idx, idx, cnt, cmd, x, y, cmdp, xp, yp, cmd0, x0, y0;
  long   *outline, *sizep, size, chd;
  unsigned int  scode, offs;

  scode = jis2c(jiscode);
  if (jiscode == 0x2121){
    if ((outline = (long*) malloc((int)(1+offset)*sizeof(long))) == NULL)
      return NULL;
    outline[offset] = 0L;
    return outline;
  }
  if ((0x2122 <= jiscode) && (jiscode <= 0x7424)){
    if (jiscode < 0x3000){
      fnt_file = 0;
    } else if (jiscode < 0x5000){
      fnt_file = 1;
    } else {
      fnt_file = 2;
    }
  } else {
    return NULL;
  }

  port  = PrimFontTable[id].Fds[fnt_file];   
  fp = VFFM_FStream(port);
  offs  = PrimFontTable[id].Headers[fnt_file]->Offset[scode];
  sizep = &PrimFontTable[id].Headers[fnt_file]->Size[scode];
  if (*sizep == EMPTY_PTR)
    CorrectSize(scode, fp, PrimFontTable[id].Headers[fnt_file]);

  if (*sizep == 0L)
    return NULL;
  if (*sizep < 0L)
    size = -3*(*sizep);  /* this is enough */
  else
    size = *sizep;
  if ((outline = (long*) malloc((int)(size+offset)*sizeof(long))) == NULL)
    return NULL;
  /***printf("  OUTLINE SIZE %5Ld\n", *sizep);***/
  /***printf("     ALLOCATED %5Ld\n", size);***/

  /***printf("=== OFFS %08x\n", offs);***/
  Seek(fp, offs);
  InitBitStream(fp);
  chd = VFD_CHAR;
  cnt = 0;
  idx = offset;

  for (;;){
NEXT_CIRCLE:
    if ((cmd = ReadXY(fp, &x, &y)) == -1)
      break;
    cmd0 = cmd; x0 = x; y0 = y;
    cmdp = cmd; xp = x; yp = y; 
    /***printf("CMD0=%d, X0=%d, Y0=%d\n", cmd0, CONV_X(x0), CONV_Y(y0));***/
    /***printf("CMD0=%d, X0=%d, Y0=%d\n", cmd0, x0, y0);***/
    token_idx = idx;
    outline[idx++] = (chd | VFD_CWCURV);
    cnt++;
    chd  = 0L;

    for (;;){ 
      cmd = ReadXY(fp, &x, &y);
      switch (cmd){
      case -1:
      END_OF_CCURV:
	if (cmdp != cmd0){
	  outline[idx++] = ((cmd0==0) ? VFD_LINE : VFD_BEZ);
	  cnt++;
	}
	outline[idx++] = VFD_MAKE_XY(xp, yp);
	cnt++;
	goto NEXT_CIRCLE;
      case 0:
      LINE:
	outline[token_idx] |= VFD_LINE;
	outline[idx++] = VFD_MAKE_XY(xp, yp);
	cnt++;
	cmdp = cmd;  xp = x; yp = y;
	cmd = ReadXY(fp, &x, &y);
	while (cmd == 0){
	  outline[idx++] = VFD_MAKE_XY(xp, yp);
	  cnt++;
	  cmdp = cmd;  xp = x; yp = y; 
	  cmd = ReadXY(fp, &x, &y);
	}
	if (cmd == -1)
	  goto END_OF_CCURV; 
	token_idx = idx;
	outline[idx++] = 0L;
	cnt++;
	goto BEZ;
      case 1:
      BEZ: 
	outline[token_idx] |= VFD_BEZ;
	outline[idx++] = VFD_MAKE_XY(xp, yp);
	cnt++;
	cmdp = cmd;  xp = x; yp = y; 
	cmd = ReadXY(fp, &x, &y);
	while (cmd == 1){
	  outline[idx++] = VFD_MAKE_XY(xp, yp);
	  cnt++;
	  cmdp = cmd;  xp = x; yp = y; 
	  cmd = ReadXY(fp, &x, &y);
	}
	if (cmd == -1)
	  goto END_OF_CCURV; 
	token_idx = idx;
	outline[idx++] = 0L;
	cnt++;
	goto LINE;
      }
    }
  }
  outline[idx++] = 0L;
  cnt++;

  if (*sizep < 0)
    *sizep = (long) cnt;
  /***printf("         SIZE %5Ld\n", *sizep);***/
  return outline;
}


static int
ReadXY(fp, xp, yp)
  FILE *fp;
  int  *xp, *yp;
{
  register int         x, y, fx, fy;

  x = Read12Bits(fp);
  y = Read12Bits(fp);
  /***printf("*** %04x %04x  \n", x, y);***/
  if ((x == JG_MAX_VALUE) && (y == JG_MAX_VALUE))
    return -1;

  *xp  = x & JG_XY_MASK;
  *yp  = y & JG_XY_MASK;
  fx   = x & JG_CMD_MASK;
  fy   = y & JG_CMD_MASK;

  if (*xp > (JG_MAX_XY+1)/2)
    *xp = (JG_MAX_XY+1) - *xp;
  else 
    *xp += (JG_MAX_XY+1)/2;
  if (*yp < (JG_MAX_XY+1)/2)
    *yp  = (JG_MAX_XY+1)/2 - *yp;

  *xp -= (JG_MAX_XY+1)/4;
  *xp = (*xp < 0) ? 0: *xp * 2;
  *yp -= (JG_MAX_XY+1)*5/16;
  *yp = (*yp < 0) ? 0: *yp * 2;
  /***printf("    %04x %04x  %1x %1x\n", *xp, *yp, fx, fy);***/
  if (fx != 0)
    return 1;
  return 0;
}


/* READ 1 BYTE INTEGER */
static int
Read1Byte(fp)
  FILE *fp; 
{
  return fgetc(fp);
}

/* READ 4 BYTE INTEGER */
static unsigned long
Read4Bytes(fp)
  FILE *fp;
{
  unsigned long i1, i2, i3, i4;
  
  i1 = (unsigned long) Read1Byte(fp);
  i2 = (unsigned long) Read1Byte(fp);
  i3 = (unsigned long) Read1Byte(fp);
  i4 = (unsigned long) Read1Byte(fp);
  return i1 + i2*0x100 + i3*0x10000 + i4*0x1000000;
}

static unsigned int   LeftBits  = 0;
static unsigned long  BitStream = 0;

/* INIT BIT STREAM */
static void
InitBitStream(fp)
  FILE *fp;
{
  BitStream = 0;
  LeftBits  = 0;
}

/* READ 12 BITS INTEGER FROM BIT STREAM */
static unsigned int 
Read12Bits(fp)
  FILE *fp;
{
  if (LeftBits < 12){
    BitStream  = BitStream * 0x10000L;
    BitStream  += (unsigned int) Read1Byte(fp);
    BitStream  += (unsigned int) Read1Byte(fp) * 0x0100L;
    LeftBits   += 16;
  }
  LeftBits -= 12;
  return (BitStream >> LeftBits) & JG_MAX_VALUE;
}

/* SEEK TO THE OFFSET */
static void 
Seek(fp, offset)
  FILE *fp;
  long offset;
{
  fseek(fp, offset, 0);
}

/* RETURN CURRENT OFFSET FOR FONT DATA */
static long
CurrentPos(fp)
  FILE *fp;
{
  return ftell(fp);
}


static int
jis2c(code)
  int  code;
{
  int  jgcode;
  
  if (code < 0x3000)
    jgcode = (((code>>8)&0xff) - 0x21)*0x5e + (code&0xff) - 0x21;
  else if (code < 0x5000)
    jgcode = (((code>>8)&0xff) - 0x30)*0x5e + (code&0xff) - 0x21;
  else 
    jgcode = (((code>>8)&0xff) - 0x50)*0x5e + (code&0xff) - 0x21;
  return jgcode;
}

/* EOF */
