+#ifndef lint
+static char sccsid[]="@(#)prects.c 1.1 (CWI) 87/07/16";
+#endif lint
+/*
+ * read the fontdir/char.rle files from cdata output to produce the
+ * rectangular data for a font.
+ */
+
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <strings.h>
+
+#include "../defs.h"
+#include "huff7.h"
+#include "huff14.h"
+#include "Ptable.h"
+
+extern long lseek();
+
+extern Word huff7[];
+extern Word huff14[];
+extern Byte Ptable[];
+
+/*
+ * bit map will be at most 1024 by 1024 points
+ *
+ * The right answer would be to compact the data in
+ * bytes, but I'm just going to hack this... (DD)
+ */
+
+#define MAXnat 1024
+#define MAX 128
+typedef unsigned short nat;
+
+Byte bitmap[MAX][MAXnat], /* `real' binary data */
+ newbitmap[MAXnat][ MAXnat]; /* expanded data in chars */
+Byte sqmap[MAXnat][MAXnat],
+ prmap[MAXnat][MAXnat],
+ uline[MAXnat];
+
+FILE *fd;
+int eoc = 0; /* signals end of a character */
+
+/*
+ * storage of 3 previous scan lines plus current working scan line
+ * 6 extra points (always of) for begin of end of scanline for predict()
+ */
+
+Byte a[1030], b[1030], c[1030], d[1030];
+ /* pointers to the scanline storage */
+Byte *sl0 = &a[3], *sl1 = &b[3], *sl2 = &c[3], *sl3 = &d[3];
+
+#define EVER ;;
+
+/*
+ * Opcodes for the huffman decoder
+ */
+
+#define OPCODE 0300
+#define FINAL 0
+#define POINT 0200
+#define SUFFIX 0100
+
+/*
+ * address bits for pointer (huffman decode)
+ */
+
+#define ADDRS 077
+#define SUFDAT 017
+
+/*
+ * Run length value types
+ */
+
+#define DUMP 1
+#define X0 2
+#define Y0 3
+#define LMAX 4
+#define RUNL 5
+
+#define Charmax 128
+
+struct Header head;
+struct Chars Char[Charmax];
+struct Rect rect;
+
+struct Rect buf[BUFSIZ]; /* global buffer to hold rects */
+struct Rect *bob = buf; /* pointer to start of buffer */
+struct Rect *eob = &buf[BUFSIZ-1]; /* pointer to end of buffer */
+struct Rect *curp = buf; /* current buffer pointer */
+long offset; /* offset in file */
+
+
+/*
+ * We start with significant bit
+ */
+
+#define BITMASK 0100000L
+
+#define dbprintf if(debug)printf
+int debug = 0;
+
+
+#define MAXFNAME 30
+char filename[MAXFNAME];
+int fdo; /* file descriptor for output file */
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int i, j;
+ DIR *dir;
+ char outfile[BUFSIZ]; /* name for output file */
+ struct direct *dirbuf;
+ char *file, *directory;
+ Word *type, *gethuff();
+ int k; /* character we are on */
+ char *p;
+
+ argv++;
+ while( --argc && *argv[0] == '-') {
+
+ switch((*argv)[1]) {
+ case 'd':
+ debug++;
+ break;
+ case 'o':
+ sprintf(outfile,"%s", (*argv)+2);
+ break;
+ default:
+ error("Unknown option %s", *argv);
+ }
+ argv++;
+ }
+
+ if(argc < 1)
+ error("No data specified");
+
+ while(argc--) {
+ directory = rindex(*argv, '/');
+ if( directory == (char *)0)
+ directory = *argv;
+ else
+ directory++;
+
+ if((dir = opendir(*argv)) == NULL)
+ error("Can't open directory %s", *argv);
+ argv++;
+ if(sscanf(directory, "%d-%d", &j, &i) == 0)
+ error("scanf error");
+ type = gethuff(i);
+ if(outfile[0] == NULL)
+ sprintf(outfile,"%s.rect", directory);
+ dbprintf("Output to file %s\n", outfile );
+ if((fdo = open(outfile,O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
+ error("open error %s\n", outfile);
+ head.magic = MAGIC;
+ bcopy(directory, head.name,strlen(directory));
+ headit();
+ setchars();
+ setoffset();
+ for(dirbuf = readdir(dir); dirbuf != NULL; dirbuf = readdir(dir) ) {
+ if(strcmp((file = dirbuf->d_name), ".") == 0 ||
+ strcmp(file, "..") == 0)
+ continue;
+ sprintf(filename,"%s/%s",directory,file);
+ p = file;
+ while(*p++)
+ ;
+ p -= 5;
+ if(strcmp(p, ".rle") != 0){
+ fprintf(stderr, "strange file %s, skipped\n", filename);
+ continue;
+ }
+ sscanf(file, "%o", &k);
+ if(k > Charmax) {
+ fprintf(stderr,"Wierd Character %s\n", filename);
+ continue;
+ }
+ chardecode(type, k-1);
+ cleanup();
+ }
+ flusho();
+ setchars();
+ }
+}
+
+
+/*
+ * gethuff:
+ * get the huff value from the directory name.
+ */
+
+Word *
+gethuff(mcode)
+int mcode;
+{
+ Word *huff;
+
+ switch(mcode) {
+ case MSC1:
+ case MSC2:
+ huff = huff7;
+ break;
+ case MSC3:
+ huff = huff14;
+ break;
+ default:
+ error("Unknown master code %#o\n", mcode);
+ }
+ return huff;
+}
+
+
+/*
+ * chardecode:
+ * decode the encode character date in gcd of
+ * pointsize code mcode
+ */
+
+int X, Y, Lmax; /* the offsets */
+int curx, cury;
+int endline;
+
+chardecode(huff, charno)
+int charno; Word *huff;
+{
+ int runl;
+
+ (void) getbit(1); /* reset the getbit routine */
+
+ curx = Char[charno].Relwidth = getnbits(8); /* ignore the first 8 bits */
+ curx = X = Char[charno].XO = huffdecode(huff);
+ cury = Y = Char[charno].YO = huffdecode(huff);
+ Lmax = Char[charno].Lmax = huffdecode(huff);
+
+ /*
+ * Lmax 18 means 17 dots, so y should go from
+ * Y to Lmax -1 ????
+ */
+ endline = Y + Lmax - 1 ;
+
+ while(!eoc) {
+ for( cury = Y ; cury <= endline; ) {
+ runl = huffdecode(huff);
+ if(!runl) { /* End of Line */
+ predict(cury, endline - cury, 1);
+ cury = endline;
+ break;
+ }
+ else {
+ predict(cury, runl, 0);
+ cury += runl;
+ if(cury >= endline)
+ break;
+ }
+ }
+ cury = Y ;
+ storescanline(curx, cury, endline);
+ swapscanp();
+ curx++;
+ }
+ Char[charno].X = curx - X ;
+ Char[charno].Y = (Lmax + Y - 2) - Y;
+ Char[charno].offset = offset;
+ setbitmap(X, Y, curx, Lmax + Y - 2);
+ maxsq();
+ prune();
+ Char[charno].Nstructs = combi();
+ dbprintf("The next offset is %ld\n", offset);
+ dbprintf("@ End of character data (%d)\n", charno);
+}
+
+
+/*
+ * huffdecode
+ *
+ * returns the runlength of the Character Generation Data
+ * using huffman decode table huff.
+ */
+
+huffdecode(huff)
+Word *huff;
+{
+ register Word data = 0;
+ register tmp;
+ register int suffix;
+
+ for(EVER) {
+ switch(data & OPCODE) {
+ case FINAL:
+ if(data == 0) {
+ tmp = (*huff | getbit(0)) & ADDRS;
+ data = *(huff + tmp);
+ if(data == 0 )
+ return(0);
+ } else {
+ tmp = data & ~FINAL;
+ return(tmp);
+ }
+ break;
+ case POINT:
+ tmp = (data | getbit(0)) & ADDRS;
+ data = *(huff + tmp);
+ break;
+ case SUFFIX:
+ tmp = data & SUFDAT;
+ suffix = getnbits(tmp);
+ if(!suffix)
+ eoc++;
+ return(suffix);
+ default:
+ error("Unknown opcode %#o\n", data);
+ }
+ }
+}
+
+
+/*
+ * get the value of n bits from the gcd
+ */
+
+getnbits(n)
+int n;
+{
+ register int i;
+ register int j;
+ unsigned int value = 0;
+
+ for(i = n; i > 0; i-- ) {
+ j = getbit(0);
+ value = (value << 1) | j;
+ if( i > sizeof(value) * 8)
+ error("Overflow in getnbits(%d)\n", i);
+ }
+ return(value);
+}
+
+
+/*
+ * return a bit from the character generation data
+ *
+ * initialise when argument is set
+ */
+
+getbit(init)
+int init;
+{
+ static bitno;
+ static unsigned int mask;
+ static unsigned int n;
+ register int bit;
+ register int k;
+
+ if(init) {
+ bitno = 1;
+ if((fd = fopen(filename, "r")) == NULL )
+ error("Cannot open %s", filename);
+ return 0;
+ } else {
+ if( (bitno - 1) % 16 == 0) {
+ bitno = 1;
+ if(( k = fread( (char *)&n, sizeof(Word), 1, fd)) != 1)
+ error("Read error %d", k);
+ mask = BITMASK;
+ }
+ }
+
+ bit = n & mask;
+ bitno++;
+ mask = mask >> 1;
+ if(bit) {
+ return(1);
+ } else {
+ return(0);
+ }
+}
+
+
+/*
+ * predict:
+ * predicts the dot on position x, y, over a runlength r.
+ * if 3th argument is set, don't generate exception point.
+ */
+
+#define P8192 020000
+#define P4096 010000
+#define P2048 004000
+#define P1024 002000
+#define P0512 001000
+#define P0256 000400
+#define P0128 000200
+#define P0064 000100
+#define P0032 000040
+#define P0016 000020
+#define P0008 000010
+#define P0004 000004
+#define P0002 000002
+#define P0001 000001
+
+#define ON 1
+#define OFF 0
+
+
+predict(y, r, e)
+register int y;
+int e, r;
+{
+ unsigned int same = 0;
+ unsigned register int mask = 0;
+ unsigned register int state = 0;
+ unsigned register int i;
+ unsigned int prev = 0, new = 0, except = 0;
+ extern unsigned int getmask();
+
+ i = r;
+ do {
+ state = except = prev = 0;
+ mask = getmask(y);
+ if(mask & P8192) {
+ mask ^= 017777;
+ prev = 1;
+ }
+ mask &= 017777;
+ same = getdot(mask);
+ if( i == 1 && e == 0) { /* exception point */
+ except = 1;
+ }
+ state = except;
+ state |= prev << 1;
+ state |= same << 2;
+ switch(state & 07) {
+ case 0:
+ case 3:
+ case 5:
+ case 6:
+ new = ON;
+ break;
+ case 1:
+ case 2:
+ case 4:
+ case 7:
+ new = OFF;
+ break;
+ default:
+ error("Unexpected state %#o\n", state);
+ }
+ storedot( new, y );
+ y++;
+ } while (--i);
+}
+
+/*
+ * find wether the dot should be the same or not
+ */
+
+#define PMASK 017774
+#define TWOBIT 03
+
+
+getdot(value)
+unsigned int value;
+{
+ register int tmp, i, j, k;
+
+ i = (value & PMASK) >> 2;
+ j = value & TWOBIT;
+ if(i > sizeof(Ptable))
+ error("Prom adressing error");
+
+ tmp = Ptable[i];
+ k = (tmp >> j) & 1;
+ return k;
+}
+
+
+/*
+ * store point in current working area
+ */
+
+storedot( dot, y)
+register unsigned int dot;
+register int y;
+{
+ if(y > Lmax + 2 + Y )
+ error("Out of range in store dot, y = %d", y);
+
+ if(y == endline -1)
+ return;
+ sl0[y] = dot;
+}
+
+
+/*
+ * construct the predict mask for position x, y
+ */
+
+unsigned int
+getmask(y)
+register int y;
+{
+ register unsigned int mask = 0;
+
+ if( y < 3 || y > 1029)
+ error("Out of range in getmask, y = %d\n", y);
+
+ if( sl3[y+2] ) /* PROM 1 */
+ mask |= P0001;
+ if( sl3[y+1] )
+ mask |= P0002;
+ if( sl3[y-1] ) /* PROM 4 */
+ mask |= P0004;
+ if( sl3[y-2] ) /* PROM 8 */
+ mask |= P0008;
+ if( sl2[y+3] ) /* PROM 16 */
+ mask |= P0016;
+ if( sl2[y+1] ) /* PROM 32 */
+ mask |= P0032;
+ if( sl2[y-1] ) /* PROM 64 */
+ mask |= P0064;
+ if( sl2[y-3] ) /* PROM 128 */
+ mask |= P0128;
+ if( sl1[y+2] ) /* PROM 256 */
+ mask |= P0256;
+ if( sl1[y+1] ) /* PROM 512 */
+ mask |= P0512;
+ if( sl1[ y ] ) /* PROM 1024 */
+ mask |= P1024;
+ if( sl1[y-1] ) /* PROM 2048 */
+ mask |= P2048;
+ if( sl1[y-3] ) /* PROM 4096 */
+ mask |= P4096;
+ if( sl0[y-1] ) /* PROM 8192 */
+ mask |= P8192;
+ return(mask);
+}
+
+
+/*
+ * swap the scan line buffers
+ */
+
+swapscanp()
+{
+ register Byte *sav;
+
+ /*
+ * swap the buffers
+ */
+ sav = sl3;
+ sl3 = sl2;
+ sl2 = sl1;
+ sl1 = sl0;
+ sl0 = sav;
+
+}
+
+
+cleanup()
+{
+ register int i;
+ register int j;
+
+ for( i = 0; i < 1030; i++)
+ a[i] = b[i] = c[i] = d[i] = 0;
+ sl0 = &a[3];
+ sl1 = &b[3];
+ sl2 = &c[3];
+ sl3 = &d[3];
+ for( i = 0; i < MAXnat; i++)
+ for( j = 0; j < MAXnat; j++) {
+ newbitmap[j][i] = 0;
+ sqmap[j][i] = 0;
+ prmap[j][i] = 0;
+ uline[j] = 0;
+ }
+ for( i = 0; i < MAXnat; i++)
+ for (j = 0; j < MAX; j++)
+ bitmap[j][i] = 0;
+ eoc = 0;
+ (void) fclose(fd);
+}
+
+
+/*
+ * store the curent scan line in the bitmap
+ *
+ * bit clumsy, we could just as well dump everyscan line each time
+ * but, as said before, we don't know what to do with the bitmap...
+ *
+ */
+
+storescanline(x, y, toy)
+register int x, y, toy;
+{
+ register int m, n, i;
+
+ m = x / 8;
+ n = x % 8;
+ if(m > MAX)
+ error("bit map overflow for x (%d)\n", m);
+
+ if(toy >= MAXnat)
+ error("Bitmap overflow");
+ for( i = y; i < toy; i++)
+ if(sl0[i])
+ bitmap[m][i] |= (1 << n);
+}
+
+short width, height;
+
+#define For_v for(v=0; v < height; v++)
+#define For_h for(h=0; h < width; h++)
+
+
+/*
+ * print the bit map
+ */
+
+setbitmap(fromx, fromy, tox, toy)
+int fromx, fromy, tox, toy;
+{
+ register int m, n;
+ register int x, y;
+ nat v, h;
+
+ width = tox - fromx;
+ height = toy - fromy;
+ if (width > MAXnat || height > MAXnat) {
+ error("*** X or Y is too large (%d %d)\n", width, height);
+ }
+
+ dbprintf("# Rectangle map of character %s\n", filename);
+ dbprintf("%% X %d Y %d\n", width, height);
+
+ for(v= 0, y = toy - 1; y >= fromy; v++, y--) {
+ for( h=0, x = fromx; x < tox; h++, x++) {
+ m = x / 8;
+ n = x % 8;
+ if((bitmap[m][y] >> n ) & 1)
+ newbitmap[v][h] = 1;
+ else
+ newbitmap[v][h] = 0;
+ }
+ }
+}
+
+
+
+maxsq()
+{
+ register nat v, h, m;
+ nat uleft, up, left;
+ For_h
+ uline[h]= 0;
+ For_v {
+ uleft= left= 0;
+ For_h {
+ up= uline[h];
+ if (newbitmap[v][h]) {
+ m= uleft;
+ if (up < m) m= up;
+ if (left < m) m= left;
+ sqmap[v][h]= ++m;
+ } else
+ sqmap[v][h]= m= 0;
+ uleft= up;
+ uline[h]= left= m;
+ }
+ sqmap[v][h]= 0;
+ }
+}
+
+
+prune()
+{
+ register nat v, h, m;
+ nat vv, hh;
+ For_v {
+ For_h {
+ m= sqmap[v][h];
+ for (vv= v; m && vv <= v+1 && vv < height; vv++)
+ for (hh= h; m && hh <= h+1 && hh < width; hh++)
+ if (sqmap[vv][hh] > m) m= 0;
+ prmap[v][h]= m;
+ }
+ }
+}
+
+
+combi()
+{
+ register nat v, h, m, p=0, hh;
+ int rects = 0; /* track number of structures written */
+
+ For_v {
+ p=m= 0;
+ for (h= 0; h <= width; h++) {
+ if (h == width || prmap[v][h] != m) {
+ /* Don't pay attention to "singletons" (h-p == 1) */
+ if (m && h-p > 1) {
+ rects++;
+ rect.yO = v-m+1;
+ rect.y = m;
+ rect.xO = p-m+1;
+ rect.x = h-1-p+m;
+ oput(rect);
+ dbprintf("> V@%3d|%3d*H@%3d|%3d\n", v-m+1, m, p-m+1, h-1-p+m);
+ /* Mark squares as accounted for */
+ for (hh= p; hh < h; hh++) sqmap[v][hh]= 0;
+ }
+ if (h < width) m= prmap[v][p= h];
+ }
+ }
+ }
+ for (h = 0; h <= width; h++) {
+ p=m= 0;
+ for (v= 0; v <= height; v++) {
+ if (v == height || prmap[v][h] != m) {
+ /* Pay attention to unaccounted-for "singletons" */
+ if (m && (v-p > 1 || sqmap[v-1][h])) {
+ rects++;
+ rect.yO = p-m+1;
+ rect.y = v-1-p+m;
+ rect.xO = h-m+1;
+ rect.x = m;
+ oput(rect);
+ dbprintf("> V@%3d|%3d*H@%3d|%3d\n", p-m+1, v-1-p+m, h-m+1, m);
+ }
+ if (v < height) m= prmap[p= v][h];
+ }
+ }
+ }
+ dbprintf("<\n");
+ dbprintf("The Nstructs should be %d\n", rects);
+ return(rects);
+}
+
+headit()
+{
+ if(lseek(fdo, (long)0, 0) == -1)
+ error("seek error in head routine");
+ if(write(fdo, (char *) &head, sizeof(struct Header)) != sizeof(struct Header))
+ error("write error in head routine");
+}
+setchars()
+{
+ if(lseek(fdo, (long)(sizeof(struct Header)), 0) == -1)
+ error("seek error in setchars routine");
+ if (write(fdo, (char *)Char, Charmax * sizeof(struct Chars)) != Charmax * sizeof(struct Chars))
+ error("Write error in setchars routine");
+}
+
+
+/* output a rect struct */
+
+oput(r)
+struct Rect r;
+{
+ *curp++ = r;
+ if(curp > eob) {
+ flusho();
+ curp = bob;
+ }
+ offset += sizeof(struct Rect);
+}
+
+/* flush the buffer holding the rectangles */
+
+flusho()
+{
+
+ if ( write(fdo, (char *)bob, (int)(curp - bob) * sizeof(struct Rect)) !=
+ (int)(curp - bob)*sizeof(struct Rect))
+ error("Write error in flusho routine");
+}
+
+setoffset()
+{
+ offset = sizeof(struct Header) + Charmax * sizeof(struct Chars);
+}