/* mangle.c --- put all characters at top-bit-set.  */

#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <kernel.h> /* Acorn sys header */

#define CHUNK(M)        ((M) * 32)

#define TRUE            (0 == 0)
#define FALSE           (0 != 0)

/* Header of IntMetrics file.  */

struct intmetrics_header
{
  char f_name[40];
  int  sixteens[2];
  int num_chars;   /* SHOULD be < 256.  */
  unsigned char mapping[256];
};

struct outlines_header
{
  char magic[4];
  unsigned int bpp:8, version:8, flags:16;
  signed int x0:16, y0:16, w:16, h:16;
  int offset[9];
};


int chunk_occupied[8] = {0, 1, 1, 1, 0, 1, 0, 0};

void
fatal (char *fmt, ...)
{
 va_list ap;

  va_start (ap, fmt);
  vfprintf (stderr, fmt, ap);
  fprintf (stderr, ".\n");
  va_end (ap);
  exit (1);
}


void *
xmalloc (size_t i)
{
  void *r = malloc (i);

  if (r == NULL && i)
    fatal ("OUT OF VM");
  return (r);
}


int
main (int argc, char **argv)
{
  char s_ol[1024], s_im[1024], cmd[1024], *dir_name, *font_name;
  FILE *f_ol, *f_im;
  struct intmetrics_header h_im;
  struct outlines_header h_ol;
  signed short *dim_in[6], *dim_out[6];
  unsigned int *chunk[8], scaffold_size, *scaffold_table;
  int map_done[256], chunk_size[8];
  int i, j, k, l, m;

  if (argc != 3)
    fatal ("usage: %s directory font", *argv);

  dir_name = argv[1];
  font_name = argv[2];

  if (strlen (font_name) > 39)
    fatal ("NEW FONT NAME TOO LONG");

  /* Open files.  */

  sprintf (s_ol, "%s.Outlines", dir_name);
  f_ol = fopen (s_ol, "rb");
  if (f_ol == NULL)
    fatal ("Failed to open `%s'", s_ol);

  sprintf (s_im, "%s.IntMetrics", dir_name);
  f_im = fopen (s_im, "rb");
  if (f_im == NULL)
    fatal ("Failed to open `%s'", s_im);


  /******** Manipulate IntMetrics.  ********/

  if (fread (&h_im, sizeof (struct intmetrics_header), 1, f_im) != 1)
    fatal ("ERROR READING METRICS HEADER");

  fputs ("Font name = ", stderr);
  for (i = 0; h_im.f_name[i] != 0xd; i++)
    fputc (h_im.f_name[i], stderr);
  fputc ('\n', stderr);

  for (i = 0; i < 8; i++)
    if (chunk_occupied[i] == 0)
      for (j = 0; j < 32; j++)
        if (h_im.mapping[i * 32 + j])
          fatal ("WRONG INTMETRICS CHUNKS OCCUPIED");

  for (i = 0; i < 32; i++)
    h_im.mapping[128 + i] = h_im.mapping[160 + i];
  for (i = 32; i < 128; i++)
    h_im.mapping[i + 128] = h_im.mapping[i];
  for (i = 0; i < 128; i++)
    h_im.mapping[i] = 0;

  for (i = 0; i < 6; i++)
    {
      j = 2 * h_im.num_chars;
      dim_in[i] = xmalloc (j + 2);
      dim_out[i] = xmalloc (j + 2);
      if (fread (dim_in[i], j, 1, f_im) != 1)
        fatal ("ERROR READING METRICS DIMENSIONS");
    }


#ifdef SHUFFLE

  /* Shuffle.  */

  l = 1;
  memset (map_done, 0, sizeof (map_done));
  for (i = 128; i < 256; i++)
    if (h_im.mapping[i] && !map_done[i])
      {
        j = h_im.mapping[i];
        for (k = 0; k < 6; k++)
          dim_out[k][l] = dim_in[k][j];
        for (m = i; m < 256; m++)
          if (h_im.mapping[m] == j)
            {
              h_im.mapping[m] = l;
              map_done[m] = TRUE;
            }
        l++;
      }

  if (l != h_im.num_chars)
    fatal ("BUG IN INTMETRICS");

#endif

  fclose (f_im);

  /******** Manipulate Outlines.  ********/

  if (fread (&h_ol, sizeof (struct outlines_header), 1, f_ol) != 1)
    fatal ("ERROR READING OUTLINES HEADER");

  if (strncmp (h_ol.magic, "FONT", 4))
    fatal ("`%s' is not a font file");

  if (h_ol.version != 4)
    fatal ("Can't cope with version %d", h_ol.version);

  scaffold_size = 0;
  if (fread (&scaffold_size, 2, 1, f_ol) != 1)
    fatal ("ERROR READING OUTLINES SCAFFOLD TABLE SIZE");


  /* The real scaffold table size actually is 2 less than the value of
     SCAFFOLD_SIZE.  */

  scaffold_size -= 2;
  scaffold_table = xmalloc (scaffold_size);

  if (fread (scaffold_table, 1, scaffold_size, f_ol) != scaffold_size)
    fatal ("ERROR READING OUTLINES SCAFFOLD TABLE");


  /* Print information contained in file.  */

  fprintf (stderr, "Font description = ");
  while ((i = fgetc (f_ol)) != EOF && i != 0)
    fputc (i, stderr);
  if (i == EOF)
    {
      fputc ('\n', stderr);
      fatal ("ERROR READING OUTLINES DESCRIPTION");
    }
  fputs (" (", stderr);
  while ((i = fgetc (f_ol)) != EOF && i != 0)
    fputc (i, stderr);
  if (i == EOF)
    {
      fputc ('\n', stderr);
      fatal ("ERROR READING OUTLINES DESCRIPTION");
    }
  fputs (")\n", stderr);

  while (ftell (f_ol) % 4)
    if ((i = fgetc (f_ol)) == EOF || i != 0)
      {
        if (i == EOF)
          fatal ("ERROR READING OUTLINES DESCRIPTION PADDING");
        else
          fprintf (stderr, "ILLEGAL OUTLINE DESCRIPTION PADDING CHARACTER %d\n", i);
      }


  /* Read chunks.  */

  for (i = 0; i < 8; i++)
    {
      if (ftell (f_ol) != h_ol.offset[i])
        fatal ("CHUNK %d WRONG POSITION AT %ld SHOULD BE %d", i, ftell (f_ol), h_ol.offset[i]);
      j = chunk_size[i] = h_ol.offset[i + 1] - h_ol.offset[i];
      if (j == 0)
        chunk[i] = NULL;
      else
        {
          if (chunk_occupied[i] == 0)
            fatal ("WRONG OUTLINE CHUNKS OCCUPIED AT CHUNK %d", i);
          chunk[i] = xmalloc (j);
          if (fread (chunk[i], 1, j, f_ol) != j)
            fatal ("ERROR READING OUTLINES CHUNK %d", i);
        }
    }

  if (ftell (f_ol) != h_ol.offset[8])
    fatal ("OUTLINES FILE IS LONGER THAN EXPECTED");


  /* Shuffle.  */

  chunk_size[4] = chunk_size[5];
  chunk[4] = chunk[5];
  for (i = 1; i < 4; i++)
    {
      chunk[i + 4] = chunk[i];
      chunk_size[i + 4] = chunk_size[i];
      chunk[i] = NULL;
      chunk_size[i] = 0;
    }


  /* Temporarily patch the offset table.  */

  h_ol.offset[0] = 0;
  for (i = 0; i < 8; i++)
    h_ol.offset[i + 1] = h_ol.offset[i] + chunk_size[i];

  fclose (f_ol);


  /******** Create directory for new font.  ********/

  sprintf (cmd, "cdir %s", font_name);
  _kernel_oscli (cmd);


  /******** Open Files.  ********/

  sprintf (s_im, "%s.IntMetrics", font_name);
  f_im = fopen (s_im, "wb");
  if (f_im == NULL)
    fatal ("ERROR OPENING `%s'", s_im);

  sprintf (s_ol, "%s.OutLines", font_name);
  f_ol = fopen (s_ol, "wb");
  if (f_ol == NULL)
    fatal ("ERROR OPENING `%s'", s_ol);


  /******** Write IntMetrics.  ********/

  sprintf (h_im.f_name, "%s", font_name);
  h_im.f_name[strlen (h_im.f_name)] = 0xd;

  if (fwrite (&h_im, sizeof (h_im), 1, f_im) != 1)
    fatal ("ERROR WRITING METRICS HEADER");

  j = h_im.num_chars * 2;
  for (i = 0; i < 6; i++)
    {
#ifdef SHUFFLE
      if (fwrite (dim_out[i], j, 1, f_im) != 1)
        fatal ("ERROR WRITING METRICS METRICS");
#else
      if (fwrite (dim_in[i], j, 1, f_im) != 1)
        fatal ("ERROR WRITING METRICS METRICS");
#endif
    }

  fclose (f_im);


  /******** Write Outlines.  ********/

  if (fwrite (&h_ol, sizeof (struct outlines_header), 1, f_ol) != 1)
    fatal ("ERROR WRITING OUTLINES HEADER");

  i = scaffold_size + 2;
  if (fwrite (&i, 2, 1, f_ol) != 1)
    fatal ("ERROR WRITING OUTLINES SCAFFOLD TABLE SIZE");

  if (fwrite (scaffold_table, scaffold_size, 1, f_ol) != 1)
    fatal ("ERROR WRITING OUTLINES SCAFFOLD TABLE");

  if (fputs (font_name, f_ol) == EOF || fputc (0, f_ol) == EOF)
    fatal ("ERROR WRITING OUTLINES FONT NAME");

  if (fputs ("Outlines", f_ol) == EOF || fputc (0, f_ol) == EOF)
    fatal ("ERROR WRITING OUTLINES FONT DESCRIPTION");

  while (ftell (f_ol) % 4)
    if (fputc (0, f_ol) == EOF)
      fatal ("ERROR WRITING OUTLINES PADDING FONT DESCRIPTION");

  j = (int) ftell (f_ol);
  for (i = 0; i < 9; i++)
    h_ol.offset[i] += j;

  for (i = 0; i < 8; i++)
    {
      if (ftell (f_ol) != h_ol.offset[i])
        fatal ("INTERNAL CONSISTENCY CHECK ERROR FOR CHUNK OFFSETS");
      if (chunk[i])
        {
          if (fwrite (chunk[i], 1, chunk_size[i], f_ol) != chunk_size[i])
            fatal ("ERROR WRITING CHUNK %d", i);
        }
    }

  if (fseek (f_ol, (long int) ((char *) &h_ol.offset[0] - (char *) &h_ol), SEEK_SET))
   fatal ("ERROR SEEK OUTLINES HEADER");
  if (fwrite (&h_ol.offset[0], 4, 9, f_ol) != 9)
    fatal ("ERROR WRITING OUTLINES CHUNK OFFSETS");

  fclose (f_ol);

  return (0);
} /* main */

/* EOF */
