#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "newobj.h"
#include "pklib.h"
#include "errormsg.h"
#include "filesrch.h"
#ifndef MAXPATHLEN
#define MAXPATHLEN 256
#endif
#define PK_PRE (char)247
#define PK_ID 89
#define PK_POST (char)245
#define PK_NOP (char)246
int dpi;
FILE *pk_file;
int tfm_lengths[12];
#define lh tfm_lengths[1]
#define bc tfm_lengths[2]
#define ec tfm_lengths[3]
#define nw tfm_lengths[4]
long checksum;
long design;
byte width_index[256];
long tfm_widths[256];
byte *bitmap;
int width;
int skip;
int height;
int hoff;
int voff;
int bytes_wide;
size_t bm_size;
byte *bitmap_end;
int pk_len;
static char searchpath[MAXPATHLEN + 1];
#define HUNKSIZE (MAXPATHLEN + 2)
struct spacenode
{
struct spacenode *next;
char *sp_end;
char sp[HUNKSIZE];
} firstnode;
static FILE *
search_tfm(char **name)
{
char *p;
FILE *f;
p = TeX_search_tfm(name);
if (p == NULL)
return NULL;
strcpy(searchpath, p);
f = fopen(searchpath, "rb");
return f;
}
static long
getlong(FILE *f)
{
unsigned long value;
value = (unsigned long)getc(f) << 24;
value |= (unsigned long)getc(f) << 16;
value |= (unsigned long)getc(f) << 8;
value |= (unsigned long)getc(f);
return value;
}
char line[82];
static byte masks[] = {0, 1, 3, 7, 017, 037, 077, 0177, 0377};
byte flag;
int pk_dyn_f;
int pk_dyn_g;
int base;
int deltas[13];
static void
tallyup(int n)
{
int m;
if (n > 208)
{
++base;
n -= 192;
for (m = 0x100; m != 0 && m < n; m <<= 4)
base += 2;
if (m != 0 && (m = (m - n) / 15) < 13)
deltas[m] += 2;
}
else if (n > 13)
++deltas[(208 - n) / 15];
else
--deltas[n - 1];
}
static Boolean odd = False;
static byte part;
static void
pk_put_nyb(int n)
{
if (odd)
{
*bitmap_end++ = (part << 4) | n;
odd = False;
}
else
{
part = n;
odd = True;
}
}
static void
pk_put_long(int n)
{
if (n >= 16)
{
pk_put_nyb(0);
pk_put_long(n / 16);
}
pk_put_nyb(n % 16);
}
static void
pk_put_count(int n)
{
if (n > pk_dyn_f)
{
if (n > pk_dyn_g)
pk_put_long(n - pk_dyn_g + 15);
else
{
pk_put_nyb(pk_dyn_f + (n - pk_dyn_f + 15) / 16);
pk_put_nyb((n - pk_dyn_f - 1) % 16);
}
}
else
pk_put_nyb(n);
}
static void
trim_bitmap(void)
{
byte *p;
byte mask;
if (width % 8 != 0)
{
mask = ~masks[8 - width % 8];
for (p = bitmap + bytes_wide - 1; p < bitmap_end; p += bytes_wide)
*p &= mask;
}
skip = 0;
mask = 0;
for (;;)
{
if (bitmap >= bitmap_end)
{
width = height = hoff = voff = 0;
return;
}
p = bitmap + bytes_wide;
while (p > bitmap)
mask |= *--p;
if (mask)
break;
++skip;
bitmap += bytes_wide;
}
height -= skip;
voff -= skip;
#ifdef DEBUG
if (skip < 2 || skip > 3)
printf("Character has %d empty rows at top\n", skip);
#endif
skip = 0;
mask = 0;
for (;;)
{
p = bitmap_end - bytes_wide;
while (p < bitmap_end)
mask |= *p++;
if (mask)
break;
++skip;
bitmap_end -= bytes_wide;
}
height -= skip;
#ifdef DEBUG
if (skip < 2 || skip > 3)
printf("Character has %d empty rows at bottom\n", skip);
#endif
skip = 0;
--width;
for (;;)
{
mask = 0;
for (p = bitmap + width / 8; p < bitmap_end; p += bytes_wide)
mask |= *p;
if (mask & (0x80 >> (width % 8)))
break;
--width;
++skip;
}
++width;
#ifdef DEBUG
if (skip < 2 || skip > 3)
printf("Character has %d empty columns at right\n", skip);
#endif
skip = 0;
for (;;)
{
mask = 0;
for (p = bitmap + skip / 8; p < bitmap_end; p += bytes_wide)
mask |= *p;
if (mask & (0x80 >> (skip % 8)))
break;
++skip;
}
width -= skip;
hoff -= skip;
#ifdef DEBUG
if (skip < 2 || skip > 3)
printf("Character has %d empty columns at left\n", skip);
#endif
bitmap += skip / 8;
skip = skip % 8;
}
static Boolean
pk_rll_cvt(void)
{
static int *counts = NULL;
static int maxcounts = 0;
unsigned int ncounts;
int *nextcount;
int *counts_end;
byte *rowptr;
byte *p;
byte mask;
byte *rowdup;
byte paint_switch;
int bits_left;
int cost;
int i;
ncounts = (width * height + 3) / 4;
if (ncounts > maxcounts)
{
if (counts != NULL)
free(counts);
counts = (int *)mymalloc((ncounts + 2) * sizeof (int));
maxcounts = ncounts;
}
counts_end = counts + ncounts;
base = 0;
memset(deltas, 0, sizeof (deltas));
rowdup = NULL;
p = rowptr = bitmap;
mask = 0x80 >> skip;
flag = 0;
paint_switch = 0;
if (*p & mask)
{
flag = 8;
paint_switch = 0xff;
}
bits_left = width;
nextcount = counts;
while (rowptr < bitmap_end)
{
int shift_count = bits_left;
for (;;)
{
if (bits_left == 0)
{
if ((p = rowptr += bytes_wide) >= bitmap_end)
break;
mask = 0x80 >> skip;
bits_left = width;
shift_count += width;
}
if (((*p ^ paint_switch) & mask) != 0)
break;
--bits_left;
mask >>= 1;
if (mask == 0)
{
++p;
while (*p == paint_switch && bits_left >= 8)
{
++p;
bits_left -= 8;
}
mask = 0x80;
}
}
if (nextcount >= counts_end)
return False;
shift_count -= bits_left;
*nextcount++ = shift_count;
tallyup(shift_count);
if (rowptr != rowdup && bits_left != width)
{
byte *p1 = rowptr;
byte *q = rowptr + bytes_wide;
int repeat_count;
while (q < bitmap_end && *p1 == *q)
{
++p1;
++q;
}
repeat_count = (p1 - rowptr) / bytes_wide;
if (repeat_count > 0)
{
*nextcount++ = -repeat_count;
if (repeat_count == 1)
--base;
else
{
++base;
tallyup(repeat_count);
}
rowptr += repeat_count * bytes_wide;
}
rowdup = rowptr;
}
paint_switch = ~paint_switch;
}
#ifdef DEBUG
for (p = bitmap; p < bitmap_end; p += bytes_wide)
{
byte *p1 = p;
int j;
mask = 0x80 >> skip;
for (j = 0; j < width; ++j)
{
putchar(*p1 & mask ? '@' : '.');
if ((mask >>= 1) == 0)
{
mask = 0x80;
++p1;
}
}
putchar('\n');
}
putchar('\n');
#endif
pk_dyn_f = 0;
cost = base += 2 * (nextcount - counts);
for (i = 1; i < 14; ++i)
{
base += deltas[i - 1];
if (base < cost)
{
pk_dyn_f = i;
cost = base;
}
}
if (cost * 4 > width * height)
return False;
pk_dyn_g = 208 - 15 * pk_dyn_f;
flag |= pk_dyn_f << 4;
bitmap_end = bitmap;
*nextcount = 0;
nextcount = counts;
while (*nextcount != 0)
{
if (*nextcount > 0)
pk_put_count(*nextcount);
else
if (*nextcount == -1)
pk_put_nyb(15);
else
{
pk_put_nyb(14);
pk_put_count(-*nextcount);
}
++nextcount;
}
if (odd)
{
pk_put_nyb(0);
++cost;
}
if (cost != 2 * (bitmap_end - bitmap))
printf("Cost miscalculation: expected %d, got %ld\n",
cost, (long)(2 * (bitmap_end - bitmap)));
pk_len = bitmap_end - bitmap;
return True;
}
static void
pk_bm_cvt(void)
{
byte *rowptr;
byte *p;
int blib1;
int bits_left;
byte *q;
int blib2;
byte nextbyte;
flag = 14 << 4;
q = bitmap;
blib2 = 8;
nextbyte = 0;
for (rowptr = bitmap; rowptr < bitmap_end; rowptr += bytes_wide)
{
p = rowptr;
blib1 = 8 - skip;
bits_left = width;
if (blib2 != 8)
{
int n;
if (blib1 < blib2)
{
nextbyte |= *p << (blib2 - blib1);
n = blib1;
}
else
{
nextbyte |= *p >> (blib1 - blib2);
n = blib2;
}
blib2 -= n;
if ((bits_left -= n) < 0)
{
blib2 -= bits_left;
continue;
}
if ((blib1 -= n) == 0)
{
blib1 = 8;
++p;
if (blib2 > 0)
{
nextbyte |= *p >> (8 - blib2);
blib1 -= blib2;
bits_left -= blib2;
if (bits_left < 0)
{
blib2 = -bits_left;
continue;
}
}
}
*q++ = nextbyte;
}
while (bits_left >= 8)
{
nextbyte = *p++ << (8 - blib1);
*q++ = nextbyte | (*p >> blib1);
bits_left -= 8;
}
nextbyte = *p << (8 - blib1);
if (bits_left > blib1)
nextbyte |= p[1] >> blib1;
blib2 = 8 - bits_left;
}
if (blib2 != 8)
*q++ = nextbyte;
pk_len = q - bitmap;
}
static void
putshort(short w)
{
putc(w >> 8, pk_file);
putc(w, pk_file);
}
static void
putmed(long w)
{
putc(w >> 16, pk_file);
putc(w >> 8, pk_file);
putc(w, pk_file);
}
static void
putlong(long w)
{
putc(w >> 24, pk_file);
putc(w >> 16, pk_file);
putc(w >> 8, pk_file);
putc(w, pk_file);
}
char
xgetc(FILE *f)
{
int c;
c = getc(f);
if (c == EOF)
oops("Premature end of file.");
return (byte)c;
}
void
TFMopen(char **filename)
{
FILE *tfm_file;
int i;
int cc;
tfm_file = search_tfm(filename);
if (tfm_file == NULL)
oops("Cannot find tfm file.");
for (i = 0; i < 12; i++)
{
int j;
j = (int)((byte)getc(tfm_file)) << 8;
tfm_lengths[i] = j | (int)((byte)xgetc(tfm_file));
}
checksum = getlong(tfm_file);
design = getlong(tfm_file);
fseek(tfm_file, 4 * (lh + 6), 0);
for (cc = bc; cc <= ec; ++cc)
{
width_index[cc] = (byte)xgetc(tfm_file);
(void)xgetc(tfm_file);
(void)xgetc(tfm_file);
(void)xgetc(tfm_file);
}
for (i = 0; i < nw; ++i)
tfm_widths[i] = getlong(tfm_file);
fclose(tfm_file);
}
void
PKopen(char *filename,
char *ident,
int resolution)
{
int ppp;
int i;
dpi = resolution;
if ((pk_file = fopen(filename, "wb")) == NULL)
{
perror(filename);
exit(1);
}
putc(PK_PRE, pk_file);
putc(PK_ID, pk_file);
i = strlen(ident);
putc(i, pk_file);
fwrite(ident, 1, i, pk_file);
putlong(design);
putlong(checksum);
ppp = dpi / 72.27 * 65536.0 + 0.5;
putlong(ppp);
putlong(ppp);
}
void
PKputglyph(int cc,
int llx, int lly, int urx, int ury,
int w, int h,
byte *b)
{
float char_width;
long dm;
long tfm_wid;
bitmap = b;
width = w;
height = h;
hoff = -llx;
voff = ury - 2;
if (width != urx - llx || height != ury - lly)
oops("Dimensions do not match: (%d - %d) (%d - %d) <=> %d %d",
llx, lly, urx, ury, width, height);
bytes_wide = (width + 7) / 8;
bm_size = bytes_wide * height;
bitmap_end = bitmap + bm_size;
trim_bitmap();
if (height == 0 || !pk_rll_cvt())
pk_bm_cvt();
if (!width_index[cc])
return;
tfm_wid = tfm_widths[width_index[cc]];
char_width = tfm_wid / 1048576.0 * design / 1048576.0 * dpi / 72.27;
dm = (long)(char_width + 0.5) - (char_width < -0.5);
if (pk_len + 8 < 4 * 256 && tfm_wid < (1<<24) &&
dm >= 0 && dm < 256 && width < 256 && height < 256 &&
hoff >= -128 && hoff < 128 && voff >= -128 && voff < 128)
{
putc(flag | ((pk_len + 8) >> 8), pk_file);
putc(pk_len + 8, pk_file);
putc(cc, pk_file);
putmed(tfm_wid);
putc(dm, pk_file);
putc(width, pk_file);
putc(height, pk_file);
putc(hoff, pk_file);
putc(voff, pk_file);
}
else if (pk_len + 13 < 3 * 65536L && tfm_wid < (1<<24) &&
dm >= 0 && dm < 65536L && width < 65536L && height < 65536L &&
hoff >= -65536L && hoff < 65536L &&
voff >= -65536L && voff < 65536L)
{
putc(flag | 4 | ((pk_len + 13) >> 16), pk_file);
putshort(pk_len + 13);
putc(cc, pk_file);
putmed(tfm_wid);
putshort(dm);
putshort(width);
putshort(height);
putshort(hoff);
putshort(voff);
}
else
{
putc(flag | 7, pk_file);
putlong(pk_len + 28);
putlong(cc);
putlong(tfm_wid);
putlong((long)(char_width * 65536.0 + 0.5) - (char_width < -0.5));
putlong(0);
putlong(width);
putlong(height);
putlong(hoff);
putlong(voff);
}
fwrite(bitmap, 1, pk_len, pk_file);
}
void
PKclose(void)
{
putc(PK_POST, pk_file);
while (ftell(pk_file) % 4 != 0)
putc(PK_NOP, pk_file);
fclose(pk_file);
}