#include <stdio.h>
#include <math.h>

/* usage */
/* type1tomf psfile > mffile */
int nohint;
main(ac,ag)
char **ag;
{
  FILE *fp;
  int len,kcode;
  char buf[4096];

  if(ac<2)exit(1);
  if(!strcmp(ag[1],"-nohint"))nohint=1,ag++;
  if((fp=fopen(ag[1],"r"))==NULL){
    fprintf(stderr,"File %s is not found\n",ag[1]);
    exit(1);
  }
  print_header();
  while(fgets(buf,4096,fp)!=NULL){
    len=strlen(buf);
    if(buf[0]=='<' && !strncmp(buf+len-6 ,"CompD",5)){
      kcode=strtol(buf+len-12,NULL,16);
      print_kanji(kcode,buf);
    }
  }
  printf("end");
  fclose(fp);
  return 0;
}
print_header()
{
  printf("font_size 10pt#;\n");
  printf("mode_setup;\n");
  printf("turningcheck := 0;\n");
}
print_kanji_header(kcode)
{
  printf("beginchar(%d,10pt#,10pt#,0pt#);\n",kcode&255);
}

int hex2bin(hexstr,binstr)
char *hexstr;
unsigned char *binstr;
{
  int len,c;

  for(len=0,hexstr++;*hexstr!='>'&&*hexstr;hexstr+=2,len++){
    c=(*hexstr>='a'?*hexstr-'a'+10:*hexstr-'0');
    *binstr++ = (c<<4)|(*(hexstr+1)>='a'?*(hexstr+1)-'a'+10:*(hexstr+1)-'0');
  }
  return len;
}

decrypt_str(cipher,plain,len)
unsigned char *cipher,*plain;
{
  unsigned short r=4330,c1=52845,c2=22719;

  while(--len>=0){
    *plain++=(*cipher ^ (r>>8));
    r=(*cipher++ +r)*c1+c2;
  }
}

show_charstr(plain,len)
unsigned char *plain;
{
  unsigned char *limit=plain+len,uc;
  int n;

  while(plain<limit){
    uc= *plain++;
    if(32 <=uc && uc<=246){
      printf("Int %d\n",(int)uc-139);
    }
    else if(247<=uc && uc<=250){
      printf("Int %d\n",((int)uc-247)*256+(*plain++)+108);
    }
    else if(251<=uc && uc<=254){
      printf("Int %d\n",-((int)uc-251)*256-(*plain++)-108);
    }
    else if(uc==255){
      printf("Int %d\n",
	     (*plain<<24)|(*(plain+1)<<16)|(*(plain+2)<<8)|(*(plain+3)));
      plain+=4;
    }
    else
      switch (uc){
      case 14:printf("endchar\n");break;
      case 13:printf("hsbw\n");break;
      case 12:
	switch(*plain++){
	case 6:
	  printf("seac\n");break;
	case 7:
	  printf("sbw\n");break;
	case 0:
	  printf("dotsection\n");break;
	case 2:
	  printf("hstem3\n");break;
	case 1:
	  printf("vstem3\n");break;
	case 12:
	  printf("div\n");break;
	case 16:
	  printf("callothersubr\n");break;
	case 17:
	  printf("pop\n");break;
	case 33:
	  printf("setcurrentpoint\n");break;
	}
	break;
      case 9:
	printf("closepath\n");break;
      case 6:
	printf("hlineto\n");break;
      case 22:
	printf("hmoveto\n");break;
      case 31:
	printf("hcvcurveto\n");break;
      case 5:
	printf("rlineto\n");break;
      case 21:
	printf("rmoveto\n");break;
      case 8:
	printf("rrcurveto\n");break;
      case 30:
	printf("vhcurveto\n");break;
      case 7:
	printf("vlineto\n");break;
      case 4:
	printf("vmoveto\n");break;
      case 1:
	printf("hstem\n");break;
      case 3:
	printf("vstem\n");break;
      case 10:
	printf("callsubr\n");break;
      case 11:
	printf("return\n");break;
      }
  }
}

#define STACKSIZE 1024
int stack[STACKSIZE];
#define PUSH(x) (*--sp=(x))
#define DISCARD(n) (sp+=n)

struct point {
  int tag,x,y;
} points[1024];  
/* tags */
#define NONE 0
#define LINE 1
#define BEZIER 2

int lcount=0;

#define PI 3.14159265358979
#define PI2 (PI*2)
double difftheta(t1,t2)
double t1,t2;
{
  double difft=t2-t1;
  if(difft<-PI)return (difft+PI2);
  else if(difft>PI) return (difft-PI2);
  else return difft;
}

double allangle(p)
{
  int i;
  double t0,t1,t2,allt;

  for(i=0;points[i+1].y==points[i].y && points[i+1].x==points[i].x;i++);
  t0=t1=atan2((double)(points[i+1].y-points[i].y),(double)(points[i+1].x-points[i].x));
  i++;
  for(allt=0.0;i<p-1;i++){
    if(points[i+1].y!=points[i].y || points[i+1].x!=points[i].x){
      t2=atan2((double)(points[i+1].y-points[i].y),(double)(points[i+1].x-points[i].x));
      allt+=difftheta(t2,t1);
/*      fprintf(stderr,"allangle=%f,t1=%f,t2=%f\n",allt,t1,t2); */
      t1=t2;
    }
  }
  if(points[0].y!=points[i].y || points[0].x!=points[i].x){
    t2=atan2((double)(points[0].y-points[i].y),(double)(points[0].x-points[i].x));
    allt+=difftheta(t2,t1);
  }
  allt+=difftheta(t0,t2);
/*  fprintf(stderr,"allangle=%f\n",allt); */
  return allt;
}

notline(x0,y0,x1,y1,x2,y2,x3,y3)
{
  int dx=x3-x0,dy=y3-y0,dx0=x1-x0,dy0=y1-y0,dx3=x3-x2,dy3=y3-y2;
  double t0,t3,difft;

  if(dx*dx+dy*dy>50)return 1;
  if(dy0==0 && dx0==0){
    if((dy3==0 && dx3==0)||(x2==x0 && y2==y0))
      return 0;
    dx0=x2-x0;dy0=y2-y0;
  }
  t0=atan2((double)dy0,(double)dx0);
  if(dx3==0 && dy3==0){
    if((x1==x3 && y1==y3)) return 0;
    dx3=x3-x1;dy3=y3-y1;
  }
  t3=atan2((double)dy3,(double)dx3);
  difft=difftheta(t3,t0);
  if(difft<-0.4 || difft>0.4) return 1;
  return 0;
}

flush_point(p)
{
  int i;
  if(p>0){
    for(i=0;i<p;i++){
      print_x(lcount+i,points[i].x);
      print_y(lcount+i,points[i].y);
    }
#if 0
    if(allangle(p)<0.0)
      printf("fill ");
    else       printf("unfill ");
#endif
    printf("fill ");
    printf("(x%d,y%d)",lcount,lcount);
    for(i=1;i<p;i++){
      switch (points[i].tag){
      case BEZIER:
	  if(notline(points[i-1].x,points[i-1].y,
		   points[i].x,points[i].y,
		   points[i+1].x,points[i+1].y,
		   points[(i+2)%p].x,points[(i+2)%p].y)){
	    printf(" .. controls (x%d,y%d) and (x%d,y%d)",
		   lcount+i,lcount+i,lcount+i+1,lcount+i+1);
	    if(i+3>p)
	      printf("\n");
	    else
	      printf("  .. (x%d,y%d)\n",
		     lcount+i+2,lcount+i+2);
	  }
	  else {
	      printf("  -- (x%d,y%d)\n",
		     lcount+(i+2)%p,lcount+(i+2)%p);
	  }
	i+=2;
	break;
      case LINE:
	printf(" -- (x%d,y%d)\n",lcount+i,lcount+i);
	break;
      }
    }
    if(points[p-1].x!=points[0].x || points[p-1].y!=points[0].y){
      printf("  .. (x%d,y%d)",lcount,lcount);
    }
    printf("  .. cycle;\n");
    lcount+=p;
  }
}

struct stems{
  int from,width,n;
} hstems[256],vstems[256];
int hstem,vstem,checked;

int compstem(c1,c2)
struct stems *c1,*c2;
{
  return c1->from - c2->from;
}

int toph,both,topv,botv;
check_stems()
{
  int i;
  if(hstem){
    hstems[hstem].from=0;
    hstems[hstem++].width=0;
    hstems[hstem].from=1000;
    hstems[hstem++].width=0;
    qsort(hstems,hstem,sizeof(struct stems),compstem);
    for(i=0;i<hstem;i++){
      hstems[i].n=lcount+i*2;
      printf("y%d=round (%d/1000.0*h);\n",lcount+i*2,hstems[i].from);
      if(i!=hstem-1)
	printf("y%d=round (y%d+min((%d/1000.0*w),max(1,(%d/1000.0*w))));\n",
	       lcount+i*2+1,
	       lcount+i*2,
	       hstems[i+1].from-hstems[i].from,
	       hstems[i].width);
      else
	printf("y%d=round (y%d+max(1,(%d/1000.0*w)));\n",
	       lcount+i*2+1,
	       lcount+i*2,
	       hstems[i].width);
    }
    lcount+=hstem*2;
  }
  if(vstem){
    vstems[vstem].from=0;
    vstems[vstem++].width=0;
    vstems[vstem].from=1000;
    vstems[vstem++].width=0;
    qsort(vstems,vstem,sizeof(struct stems),compstem);
    for(i=0;i<vstem;i++){
      vstems[i].n=lcount+i*2;
      printf("x%d=round (%d/1000.0*h);\n",lcount+i*2,vstems[i].from);
      if(i!=vstem-1)
	printf("x%d=round (x%d+min((%d/1000.0*h),max(1,(%d/1000.0*h))));\n",
	       lcount+i*2+1,lcount+i*2,
	       vstems[i+1].from-vstems[i].from,vstems[i].width);
      else
	printf("x%d=round (x%d+max(1,(%d/1000.0*h)));\n",
	       lcount+i*2+1,lcount+i*2,
	       vstems[i].width);
    }
    lcount+=vstem*2;
  }
  checked=1;
}
print_x(index,x)
{
  int i;
  
  if(checked && vstem){
    for(i=1;i<vstem;i++){
      if(x<vstems[i].from){
	printf("x%d=x%d+(x%d-x%d)/%d*%d;\n",index,
	       vstems[i-1].n+1,vstems[i].n,vstems[i-1].n+1,
	       vstems[i].from-vstems[i-1].from-vstems[i-1].width,
	       x-vstems[i-1].from-vstems[i-1].width);
	return;
      }
      else if(x<=vstems[i].from+vstems[i].width){
	printf("x%d=x%d+(x%d-x%d)/%d*%d;\n",index,
	       vstems[i].n,vstems[i].n+1,vstems[i].n,
	       vstems[i].width,
	       x-vstems[i].from);
	return;
      }
    }
    printf("x%d=(%d/1000.0*w);\n",index,x);
  }
  else
    printf("x%d=(%d/1000.0*w);\n",index,x);
}
print_y(index,y)
{
  int i;
  
  if(checked && hstem){
    for(i=1;i<hstem;i++){
      if(y<hstems[i].from){
	printf("y%d=y%d+(y%d-y%d)/%d*%d;\n",index,
	       hstems[i-1].n+1,hstems[i].n,hstems[i-1].n+1,
	       hstems[i].from-hstems[i-1].from-hstems[i-1].width,
	       y-hstems[i-1].from-hstems[i-1].width);
	return;
      }
      else if(y<=hstems[i].from+hstems[i].width){
	printf("y%d=y%d+(y%d-y%d)/%d*%d;\n",index,
	       hstems[i].n,hstems[i].n+1,hstems[i].n,
	       hstems[i].width,
	       y-hstems[i].from);
	return;
      }
    }
    printf("y%d=(%d/1000.0*h);\n",index,y);
  }
  else
    printf("y%d=(%d/1000.0*h);\n",index,y);
}
mf_parse_stem(plain,len)
unsigned char *plain;
{
  unsigned char *limit=plain+len,uc;
  int n;
  int *sp=stack+STACKSIZE;
  int x=0,y=0,p=0;

  while(plain<limit){
    uc= *plain++;
    if(32 <=uc && uc<=246)
      PUSH((int)uc-139);
    else if(247<=uc && uc<=250)
      PUSH(((int)uc-247)*256+(*plain++)+108);
    else if(251<=uc && uc<=254)
      PUSH(-((int)uc-251)*256-(*plain++)-108);
    else if(uc==255){
      PUSH((*plain<<24)|(*(plain+1)<<16)|(*(plain+2)<<8)|(*(plain+3)));
      plain+=4;
    }
    else
      switch (uc){
      case 14:/* printf("endchar\n"); */
	break;
      case 13:/* printf("hsbw\n"); */
	DISCARD(2);
	break;
      case 12:
	switch(*plain++){
	case 6:/* printf("seac\n"); */
	  DISCARD(5);
	  break;
	case 7:/* printf("sbw\n"); */
	  DISCARD(4);
	  break;
	case 0: /* printf("dotsection\n"); */
	  break;
	case 2:/* printf("hstem3\n"); */
	  DISCARD(6);
	  break;
	case 1:/* printf("vstem3\n"); */
	  DISCARD(6);
	  break;
	case 12:/* printf("div\n"); */
	  DISCARD(2);
	  break;
	case 16:/* printf("callothersubr\n"); */
	  DISCARD(sp[1]+2);
	  break;
	case 17:/* printf("pop\n"); */
	  DISCARD(1);
	  break;
	case 33:/* printf("setcurrentpoint\n"); */
	  DISCARD(2);
	  break;
	}
	break;
      case 9: /* printf("closepath\n"); */
	break;
      case 6: /* printf("hlineto\n"); */
	DISCARD(1);
	break;
      case 22: /* printf("hmoveto\n"); */
	DISCARD(1);
	break;
      case 31:/* printf("hvcurveto\n"); */
	DISCARD(4);
	break;
      case 5:/*	printf("rlineto\n"); */
	DISCARD(2);
	break;
      case 21:/* printf("rmoveto\n"); */
	DISCARD(2);
	break;
      case 8:/*	printf("rrcurveto\n"); */
	DISCARD(6);
	break;
      case 30:/* printf("vhcurveto\n"); */
	DISCARD(4);
	break;
      case 7: /* printf("vlineto\n"); */
	DISCARD(1);
	break;
      case 4:/* printf("vmoveto\n"); */
	DISCARD(1);
	break;
      case 1:/* printf("hstem\n"); */
	hstems[hstem].from=sp[1];
	hstems[hstem++].width=sp[0];
	DISCARD(2);
	break;
      case 3:/*	printf("vstem\n"); */
	vstems[vstem].from=sp[1];
	vstems[vstem++].width=sp[0];
	DISCARD(2);
	break;
      case 10:/* printf("callsubr\n"); */
	DISCARD(1);
	break;
      case 11:/* printf("return\n"); */
	break;
      }
  }
  check_stems();
}
mf_charstr(plain,len)
unsigned char *plain;
{
  unsigned char *limit=plain+len,uc;
  int n;
  int *sp=stack+STACKSIZE;
  int x=0,y=0,p=0;

  while(plain<limit){
    uc= *plain++;
    if(32 <=uc && uc<=246)
      PUSH((int)uc-139);
    else if(247<=uc && uc<=250)
      PUSH(((int)uc-247)*256+(*plain++)+108);
    else if(251<=uc && uc<=254)
      PUSH(-((int)uc-251)*256-(*plain++)-108);
    else if(uc==255){
      PUSH((*plain<<24)|(*(plain+1)<<16)|(*(plain+2)<<8)|(*(plain+3)));
      plain+=4;
    }
    else
      switch (uc){
      case 14:/* printf("endchar\n"); */
	flush_point(p);p=0;
	break;
      case 13:/* printf("hsbw\n"); */
	DISCARD(2);
	break;
      case 12:
	switch(*plain++){
	case 6:/* printf("seac\n"); */
	  DISCARD(5);
	  break;
	case 7:/* printf("sbw\n"); */
	  DISCARD(4);
	  break;
	case 0: /* printf("dotsection\n"); */
	  break;
	case 2:/* printf("hstem3\n"); */
	  DISCARD(6);
	  break;
	case 1:/* printf("vstem3\n"); */
	  DISCARD(6);
	  break;
	case 12:/* printf("div\n"); */
	  DISCARD(2);
	  break;
	case 16:/* printf("callothersubr\n"); */
	  DISCARD(sp[1]+2);
	  break;
	case 17:/* printf("pop\n"); */
	  DISCARD(1);
	  break;
	case 33:/* printf("setcurrentpoint\n"); */
	  DISCARD(2);
	  break;
	}
	break;
      case 9: /* printf("closepath\n"); */
	flush_point(p);p=0;
	break;
      case 6: /* printf("hlineto\n"); */
	x+= *sp++;
	points[p].tag=LINE;
	points[p].x=x;
	points[p++].y=y;
	break;
      case 22: /* printf("hmoveto\n"); */
	x+= *sp++;
	flush_point(p);p=0;
	points[p].tag=NONE;
	points[p].x=x;
	points[p++].y=y;
	break;
      case 31:/* printf("hvcurveto\n"); */
	x+= sp[3];
	points[p].tag=BEZIER;
	points[p].x=x;
	points[p++].y=y;
	x+=sp[2];y+=sp[1];
	points[p].tag=BEZIER;
	points[p].x=x;
	points[p++].y=y;
	y+=sp[0];
	points[p].tag=BEZIER;
	points[p].x=x;
	points[p++].y=y;
	DISCARD(4);
	break;
      case 5:/*	printf("rlineto\n"); */
	y+= *sp++;x+= *sp++;
	points[p].tag=LINE;
	points[p].x=x;
	points[p++].y=y;
	break;
      case 21:/* printf("rmoveto\n"); */
	y+= *sp++;x+= *sp++;
	flush_point(p);p=0;
	points[p].tag=NONE;
	points[p].x=x;
	points[p++].y=y;
	break;
      case 8:/*	printf("rrcurveto\n"); */
	x+= sp[5];y+=sp[4];
	points[p].tag=BEZIER;
	points[p].x=x;
	points[p++].y=y;
	x+=sp[3];y+=sp[2];
	points[p].tag=BEZIER;
	points[p].x=x;
	points[p++].y=y;
	x+=sp[1];y+=sp[0];
	points[p].tag=BEZIER;
	points[p].x=x;
	points[p++].y=y;
	DISCARD(6);
	break;
      case 30:/* printf("vhcurveto\n"); */
	y+=sp[3];
	points[p].tag=BEZIER;
	points[p].x=x;
	points[p++].y=y;
	x+=sp[2];y+=sp[1];
	points[p].tag=BEZIER;
	points[p].x=x;
	points[p++].y=y;
	x+=sp[0];
	points[p].tag=BEZIER;
	points[p].x=x;
	points[p++].y=y;
	DISCARD(4);
	break;
      case 7: /* printf("vlineto\n"); */
	y+= *sp++;
	points[p].tag=LINE;
	points[p].x=x;
	points[p++].y=y;
	break;
      case 4:/* printf("vmoveto\n"); */
	y+= *sp++;
	flush_point(p);p=0;
	points[p].tag=NONE;
	points[p].x=x;
	points[p++].y=y;
	break;
      case 1:/* printf("hstem\n"); */
	DISCARD(2);
	break;
      case 3:/*	printf("vstem\n"); */
	DISCARD(2);
	break;
      case 10:/* printf("callsubr\n"); */
	DISCARD(1);
	break;
      case 11:/* printf("return\n"); */
	break;
      }
  }
}

print_kanji(kcode,buf)
int kcode;
char *buf;
{
  int len;
  unsigned bbuf[4096];
  unsigned plain[4096];

  len=hex2bin(buf,bbuf);
  decrypt_str(bbuf,plain,len);
  print_kanji_header(kcode);
  lcount=hstem=vstem=checked=0;
  if(!nohint)
    mf_parse_stem(plain,len);
  mf_charstr(plain,len);
  printf("endchar;\n");
}