#include<stdio.h>
#include<stdlib.h>  /* exit() */
#include<stdarg.h>
#include<string.h>
#include<sys/stat.h>

/* PFB headers:

   0x80, sect type (1 byte, as below), sect length (4 bytes, little endian)

   1 is ASCII section,
   2 is eexec section,
   3 (with no length) is EOF

*/

static char *strnstr(const char *s1, const char *s2, size_t len){
  size_t l1,l2;

  /* Don't go past any NULL in s1 */
  for(l1=0;(l1<len)&&(s1[l1]);l1++);

  l2=strlen(s2);
  if (l2==0) return NULL;

  while(l1>=l2){
    if(!strncmp(s1,s2,l2)) return (char*)s1;
    s1++;
    l1--;
  }
  return NULL;
}


int main(int argc, char **argv)
{
  unsigned short int c1,c2,r;
  int i;
  unsigned int lengtha,lengthe;
  unsigned char *data,*eexec,header[6],*ptr;
  unsigned char cipher,plain;
  FILE *font;
  struct stat pfbstat;

  font=fopen(argv[1],"rb");
  if(!font){
    fprintf(stderr,"Error, unable to open %s for reading.\n",argv[1]);
    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);
  if(!data){
    fprintf(stderr,"Malloc error.\n");
    exit(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);
  }

  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);
  if(!eexec){
    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);
  }


  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;
  }

  fprintf(stderr,"Decryption over\n");

  /* Write font without eexec */

  ptr=strnstr(data,"eexec",lengtha);
  if (ptr) lengtha=ptr-data;
  ptr=strnstr(data+lengtha-100,"currentfile",100);
  if (ptr) lengtha=ptr-data;


  for(i=0;i<lengtha;i++) putchar(data[i]);
  printf("\nsystemdict begin\n");

  ptr=strnstr(eexec+4,"closefile",lengthe-4);
  if (ptr) lengthe=ptr-eexec;
  ptr=strnstr(eexec+lengthe-100,"currentfile",100);
  if (ptr) lengthe=ptr-eexec;

  for(i=4;i<lengthe;i++) putchar(eexec[i]);
  printf("\nend cleartomark\n");
}
