/* Issues:
 * ignores most things when setting font flags
 * sets CapHeight to boundingbox
 * ignores encoding
 * does not attempt subsetting
 *
 * One required parameter of a PDF FontDescriptor, /StemV, is
 *  equivalent to the PS parameter /StdVW. Unfortunately /StdVW is
 *  in the eexec part of the font, so this needs to be decoded.
 */

#include<stdio.h>
#include<stdlib.h>  /* exit() */
#include<stdarg.h>
#include<string.h>
#include<math.h>
#include<unistd.h>

#include "fig2pdf.h"

void settmpdir(void);
char* dict_get_key(char *dict, char *key, int len);

extern char dirname[20];

#define BLEN 100
#define PATH_MAX 257

void write_font(char *fontname){
  unsigned short int c1,c2,r;
  int i,len,fflags,stemv,debug;
  char tmp_file[30],fnt_file[30],wid_file[3],cmd[50],buff[BLEN];
  char old_dir[PATH_MAX];
  int bbox[4];
  unsigned int lengtha,lengthe,lengthes;
  char *data,*p;
  unsigned char *eexec,*eexec_old,header[6],*eexecs;
  unsigned char cipher,plain;
  double iangle;
  FILE *gs,*font,*widths;
  static int count=0;

  debug=flags&DEBUG_MASK;
  getcwd(old_dir,PATH_MAX);

  if (dirname[0]==0) settmpdir();

  chdir(dirname);

  sprintf(tmp_file,"x-f%d.ps",count);
  sprintf(fnt_file,"x-f%d.pfb",count);
  sprintf(wid_file,"x-f%d.wid",count);

  gs=fopen(tmp_file,"w+");
  if (!gs) {
    fprintf(stderr,"Unable to create temp file %s\n",tmp_file);
    perror("");
    exit(1);
  }

  /* Construct gs program for producing font we want */

  fprintf(gs,"%%!\n"
	  "/copyfile {\n"
          " 0 mark 32000 string\n"
	  "  { 4 index 1 index readstring\n"
	  "  exch 5 index 1 index writestring\n"
	  "  length 5 -1 roll add 4 1 roll\n"
	  "  not { exit } if\n"
	  "  } loop\n"
	  " cleartomark 3 -1 roll closefile\n"
	  " pop closefile\n"
	  "} bind def\n\n");

  fprintf(gs,"/%s findfont /PathLoad get (r) file\n",fontname);
  fprintf(gs,"(%s) (w) file copyfile\n\n",fnt_file);
  fprintf(gs,"/widths (%s) (w) file def\n",wid_file);
  fprintf(gs,"/%s findfont\n"
	  "0 1 /%s findfont /FontMatrix get itransform exch pop\n"
	  "scalefont setfont\n",fontname,fontname);
  fprintf(gs,"/c 1 string def\n"
	  "/num 6 string def\n"
	  "32 1 255 { dup 8 mod 0 eq {widths (\\n) writestring} if\n"
	  "c exch 0 exch put c stringwidth pop cvi num cvs\n"
	  " widths exch writestring widths ( ) writestring } for\n");
  fclose(gs);

  /* Run gs */

  sprintf(cmd,"gs -q -dNOPAUSE -dNODISPLAY -dBATCH %s",tmp_file);
  if (system(cmd)){
    fprintf(stderr,"%s failed\n",cmd);
    exit(1);
  }

  /* Open font file created */

  font=fopen(fnt_file,"rb");
  if(!font){
    fprintf(stderr,"Error, unable to open %s for reading.\n",fnt_file);
    exit(1);
  }

  i=fread(header,1,6,font);

  if(i!=6){
    fprintf(stderr,"Error reading font header\n");
    exit(1);
  }

  if((header[0]!=0x80)||(header[1]!=1)){
    fprintf(stderr,"Error in font header\n");
    exit(1);
  }

  lengtha=header[2]+(header[3]<<8)+(header[4]<<16)+(header[5]<<24);
  data=malloc(lengtha+1);
  if(!data){
    fprintf(stderr,"Malloc error.\n");
    exit(1);
  }

  if (debug>1)
    fprintf(stderr,"Reading ASCII section length %d\n",lengtha);

  if(fread(data,lengtha,1,font)==0){
    fprintf(stderr,"Error reading ASCII section of font\n");
    exit(1);
  }
  data[lengtha]=0; /* Make this section a null-terminated string */

  i=fread(header,1,6,font);

  if(i!=6){
    fprintf(stderr,"Error reading second font header\n");
    exit(1);
  }

  if((header[0]!=0x80)||(header[1]!=2)){
    fprintf(stderr,"Error in second font header\n");
    exit(1);
  }

  lengthe=header[2]+(header[3]<<8)+(header[4]<<16)+(header[5]<<24);
  eexec=malloc(lengthe+1);
  if(!eexec){
    fprintf(stderr,"Malloc error.\n");
    exit(1);
  }
  eexec_old=malloc(lengthe);
  if(!eexec_old){
    fprintf(stderr,"Malloc error.\n");
    exit(1);
  }

  if(fread(eexec,lengthe,1,font)==0){
    fprintf(stderr,"Error reading encrypted section of font\n");
    exit(1);
  }

  memcpy(eexec_old,eexec,lengthe);

  c1=52845;
  c2=22719;
  r=55665;

  for(i=0;i<lengthe;i++){
    cipher=eexec[i];
    plain=(cipher^(r>>8));
    r=(cipher+r)*c1+c2;
    eexec[i]=plain;
  }

  /* The eexec section might start with some null bytes, which confuses
   * string scanning
   */

  eexecs=eexec;
  lengthes=lengthe;
  while((lengthes)&&(!*eexecs)) {eexecs++; lengthes--;}

  if (debug>2)
    fprintf(stderr,"Eexec decryption over\n");

  OBJ_PRN("<< /Type /Font\n"
	  " /Subtype /Type1\n"
	  " /BaseFont /%s\n"
          " /FirstChar 32\n"
	  " /LastChar 255\n"
          " /Widths %d 0 R\n"
	  " /FontDescriptor %d 0 R >>\n"
	  "endobj\n\n",fontname,cref+1,cref+2);

  widths=fopen(wid_file,"rb");
  if(!widths){
    fprintf(stderr,"Error, unable to open %s for reading.\n",wid_file);
    exit(1);
  }
  OBJ_PRN("[");
  len=0;
  while((i=fread(buff,1,BLEN,widths))){
    fwrite(buff,1,i,pdf);
    len+=i;
  }
  xref[cref]+=len;
  xref[cref]+=fprintf(pdf,"]\nendobj\n\n");

  fflags=32;
  
  p=dict_get_key(data,"/FontBBox",lengtha);
  if(!p){
    fprintf(stderr,"No /FontBBox found\n");
    exit(1);
  }

  i=sscanf(p,"{%d %d %d %d",bbox,bbox+1,bbox+2,bbox+3);
  if (i!=4){
    fprintf(stderr,"Error parsing /FontBBox\n");
    exit(1);
  }

  iangle=0;
  p=dict_get_key(data,"/ItalicAngle",lengtha);
  if(p) sscanf(p,"%lf",&iangle);
  if (iangle) fflags+=64;

  p=dict_get_key((char*)eexecs,"/StdVW",lengthes);
  if((!p)||(*(p)!='[')){
    fprintf(stderr,"No /StdVW found here\n");
    exit(1);
  }
  p++;
  sscanf(p,"%d",&stemv);

  OBJ_PRN("<< /Type /FontDescriptor\n"
	  "/FontName /%s\n"
	  "/Flags %d\n"
	  "/FontBBox [%d %d %d %d]\n"
	  "/ItalicAngle %f\n"
	  "/Ascent %d\n"
	  "/Descent %d\n"
	  "/CapHeight %d\n"
	  "/StemV %d\n"
	  "/FontFile %d 0 R >>\n"
          "endobj\n\n",fontname,fflags,
	  bbox[0],bbox[1],bbox[2],bbox[3],iangle,
	  bbox[3],bbox[1],bbox[3],stemv,cref+1);

  OBJ_PRN("<< /Length1 %d /Length2 %d /Length3 0\n"
	    " /Length %d>>\nstream\n",lengtha,lengthe,lengtha+lengthe);

  fwrite(data,1,lengtha,pdf);
  xref[cref]+=lengtha;
  fwrite(eexec_old,1,lengthe,pdf);
  xref[cref]+=lengthe;
  
  xref[cref]+=fprintf(pdf,"\nendstream\nendobj\n\n");

  free(data);
  free(eexec);
  free(eexec_old);

  count++;

}
