1 #ifndef lint
2 static char sccsid[]="@(#)prects.c	1.1	(CWI)	87/07/16";
3 #endif lint
4 /*
5  * read the fontdir/char.rle files from cdata output to produce the
6  * rectangular data for a font.
7  */
8 
9 #include <sys/types.h>
10 #include <sys/dir.h>
11 #include <sys/file.h>
12 #include <stdio.h>
13 #include <strings.h>
14 
15 #include "../defs.h"
16 #include "huff7.h"
17 #include "huff14.h"
18 #include "Ptable.h"
19 
20 extern long lseek();
21 
22 extern Word	huff7[];
23 extern Word	huff14[];
24 extern Byte	Ptable[];
25 
26 /*
27  * bit map will be at most 1024 by 1024 points
28  *
29  * The right answer would be to compact the data in
30  * bytes, but I'm just going to hack this... (DD)
31  */
32 
33 #define MAXnat	1024
34 #define MAX	128
35 typedef unsigned short nat;
36 
37 Byte bitmap[MAX][MAXnat], 		/* `real' binary data		*/
38      newbitmap[MAXnat][ MAXnat];	/* expanded data in chars	*/
39 Byte sqmap[MAXnat][MAXnat],
40      prmap[MAXnat][MAXnat],
41      uline[MAXnat];
42 
43 FILE *fd;
44 int eoc = 0;	/* signals end of a character */
45 
46 /*
47  * storage of 3 previous scan lines plus current working scan line
48  * 6 extra points (always of) for begin of end of scanline for predict()
49  */
50 
51 Byte a[1030], b[1030], c[1030], d[1030];
52 	/* pointers to the scanline storage */
53 Byte *sl0 = &a[3], *sl1 = &b[3], *sl2 = &c[3], *sl3 = &d[3];
54 
55 #define EVER	;;
56 
57 /*
58  * Opcodes for the huffman decoder
59  */
60 
61 #define OPCODE	0300
62 #define FINAL	0
63 #define POINT	0200
64 #define SUFFIX	0100
65 
66 /*
67  * address bits for pointer (huffman decode)
68  */
69 
70 #define ADDRS	077
71 #define SUFDAT	017
72 
73 /*
74  * Run length value types
75  */
76 
77 #define DUMP	1
78 #define X0	2
79 #define Y0	3
80 #define LMAX	4
81 #define RUNL	5
82 
83 #define Charmax 128
84 
85 struct Header head;
86 struct Chars Char[Charmax];
87 struct Rect rect;
88 
89 struct Rect buf[BUFSIZ];		/* global buffer to hold rects */
90 struct Rect *bob = buf;			/* pointer to start of buffer */
91 struct Rect *eob = &buf[BUFSIZ-1];	/* pointer to end of buffer */
92 struct Rect *curp = buf;		/* current buffer pointer */
93 long offset;				/* offset in file */
94 
95 
96 /*
97  * We start with significant bit
98  */
99 
100 #define BITMASK	0100000L
101 
102 #define dbprintf if(debug)printf
103 int debug = 0;
104 
105 
106 #define MAXFNAME 30
107 char filename[MAXFNAME];
108 int fdo; 			/* file descriptor for output file */
109 
110 main(argc, argv)
111 int argc;
112 char **argv;
113 {
114 	int i, j;
115 	DIR *dir;
116 	char  outfile[BUFSIZ];	/* name for output file */
117 	struct direct *dirbuf;
118 	char *file, *directory;
119 	Word *type, *gethuff();
120 	int k;  		/* character we are on */
121 	char *p;
122 
123 	argv++;
124 	while( --argc && *argv[0] == '-') {
125 
126 		switch((*argv)[1]) {
127 			case 'd':
128 				debug++;
129 				break;
130 			case 'o':
131 				sprintf(outfile,"%s", (*argv)+2);
132 				break;
133 			default:
134 				error("Unknown option %s", *argv);
135 		}
136 		argv++;
137 	}
138 
139 	if(argc < 1)
140 		error("No data specified");
141 
142 	while(argc--) {
143 		directory = rindex(*argv, '/');
144 		if( directory == (char *)0)
145 			directory = *argv;
146 		else
147 			directory++;
148 
149 		if((dir = opendir(*argv)) == NULL)
150 			error("Can't open directory %s", *argv);
151 		argv++;
152 		if(sscanf(directory, "%d-%d", &j, &i) == 0)
153 			error("scanf error");
154 		type = gethuff(i);
155 		if(outfile[0] == NULL)
156 			sprintf(outfile,"%s.rect", directory);
157 		dbprintf("Output to file %s\n", outfile );
158 		if((fdo = open(outfile,O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
159 			error("open error %s\n", outfile);
160 		head.magic = MAGIC;
161 		bcopy(directory, head.name,strlen(directory));
162 		headit();
163 		setchars();
164 		setoffset();
165 		for(dirbuf = readdir(dir); dirbuf != NULL; dirbuf = readdir(dir) ) {
166 			if(strcmp((file = dirbuf->d_name), ".") == 0 ||
167 				strcmp(file, "..") == 0)
168 				continue;
169 			sprintf(filename,"%s/%s",directory,file);
170 			p = file;
171 			while(*p++)
172 				;
173 			p -= 5;
174 			if(strcmp(p, ".rle") != 0){
175 				fprintf(stderr, "strange file %s, skipped\n",  filename);
176 				continue;
177 			}
178 			sscanf(file, "%o", &k);
179 			if(k >  Charmax) {
180 				fprintf(stderr,"Wierd Character  %s\n", filename);
181 				continue;
182 			}
183 			chardecode(type, k-1);
184 			cleanup();
185 		}
186 		flusho();
187 		setchars();
188 	}
189 }
190 
191 
192 /*
193  * gethuff:
194  *	get the huff value from the directory name.
195  */
196 
197 Word *
198 gethuff(mcode)
199 int mcode;
200 {
201 	Word *huff;
202 
203 	switch(mcode) {
204 		case MSC1:
205 		case MSC2:
206 			huff = huff7;
207 			break;
208 		case MSC3:
209 			huff = huff14;
210 			break;
211 		default:
212 			error("Unknown master code %#o\n", mcode);
213 	}
214 	return huff;
215 }
216 
217 
218 /*
219  * chardecode:
220  *	decode the encode character date in gcd of
221  *	pointsize code mcode
222  */
223 
224 int X, Y, Lmax;	/* the offsets */
225 int curx, cury;
226 int endline;
227 
228 chardecode(huff, charno)
229 int charno; Word *huff;
230 {
231 	int runl;
232 
233 	(void) getbit(1);	/* reset the getbit routine */
234 
235 	curx = Char[charno].Relwidth =  getnbits(8);	/* ignore the first 8 bits */
236 	curx = X = Char[charno].XO = huffdecode(huff);
237 	cury = Y = Char[charno].YO = huffdecode(huff);
238 	Lmax = Char[charno].Lmax = huffdecode(huff);
239 
240 	/*
241 	 * Lmax 18 means 17 dots, so y should go from
242 	 * Y to Lmax -1 ????
243 	 */
244 	endline = Y + Lmax - 1 ;
245 
246 	while(!eoc) {
247 		for( cury = Y ; cury <= endline; ) {
248 			runl = huffdecode(huff);
249 			if(!runl) {		/* End of Line */
250 				predict(cury, endline - cury, 1);
251 				cury = endline;
252 				break;
253 			}
254 			else {
255 				predict(cury, runl, 0);
256 				cury += runl;
257 				if(cury >= endline)
258 					break;
259 			}
260 		}
261 		cury =  Y ;
262 		storescanline(curx, cury, endline);
263 		swapscanp();
264 		curx++;
265 	}
266 	Char[charno].X = curx - X ;
267 	Char[charno].Y = (Lmax + Y - 2) - Y;
268 	Char[charno].offset = offset;
269 	setbitmap(X, Y, curx, Lmax + Y - 2);
270 	maxsq();
271 	prune();
272 	Char[charno].Nstructs =	combi();
273 	dbprintf("The next offset is %ld\n", offset);
274 	dbprintf("@ End of character data (%d)\n", charno);
275 }
276 
277 
278 /*
279  * huffdecode
280  *
281  * returns the runlength of the Character Generation Data
282  * using huffman decode table huff.
283  */
284 
285 huffdecode(huff)
286 Word *huff;
287 {
288 	register Word data = 0;
289 	register tmp;
290 	register int suffix;
291 
292 	for(EVER) {
293 		switch(data & OPCODE) {
294 			case FINAL:
295 				if(data == 0) {
296 					tmp = (*huff | getbit(0)) & ADDRS;
297 					data = *(huff + tmp);
298 					if(data == 0 )
299 						return(0);
300 				} else {
301 					tmp = data & ~FINAL;
302 					return(tmp);
303 				}
304 				break;
305 			case POINT:
306 				tmp =  (data | getbit(0)) & ADDRS;
307 				data = *(huff + tmp);
308 				break;
309 			case SUFFIX:
310 				tmp = data & SUFDAT;
311 				suffix = getnbits(tmp);
312 				if(!suffix)
313 					eoc++;
314 				return(suffix);
315 			default:
316 				error("Unknown opcode %#o\n", data);
317 		}
318 	}
319 }
320 
321 
322 /*
323  * get the value of n bits from the gcd
324  */
325 
326 getnbits(n)
327 int n;
328 {
329 	register int i;
330 	register int j;
331 	unsigned int value = 0;
332 
333 	for(i = n; i > 0; i-- ) {
334 		j = getbit(0);
335 		value = (value << 1) | j;
336 		if( i > sizeof(value) * 8)
337 			error("Overflow in getnbits(%d)\n", i);
338 	}
339 	return(value);
340 }
341 
342 
343 /*
344  * return a bit from the character generation data
345  *
346  * initialise when argument is set
347  */
348 
349 getbit(init)
350 int init;
351 {
352 	static bitno;
353 	static unsigned int mask;
354 	static unsigned int n;
355 	register int bit;
356 	register int k;
357 
358 	if(init) {
359 		bitno = 1;
360 		if((fd = fopen(filename, "r")) == NULL )
361 			error("Cannot open %s", filename);
362 		return 0;
363 	} else {
364 		if( (bitno - 1) % 16 == 0) {
365 			bitno = 1;
366 			if(( k = fread( (char *)&n, sizeof(Word), 1, fd)) != 1)
367 				error("Read error %d", k);
368 			mask = BITMASK;
369 		}
370 	}
371 
372 	bit = n & mask;
373 	bitno++;
374 	mask = mask >> 1;
375 	if(bit) {
376 		return(1);
377 	} else {
378 		return(0);
379 	}
380 }
381 
382 
383 /*
384  * predict:
385  * predicts the dot on position x, y, over a runlength r.
386  * if 3th argument is set, don't generate exception point.
387  */
388 
389 #define P8192	020000
390 #define P4096	010000
391 #define P2048	004000
392 #define P1024	002000
393 #define P0512	001000
394 #define P0256	000400
395 #define P0128	000200
396 #define P0064	000100
397 #define P0032	000040
398 #define P0016	000020
399 #define P0008	000010
400 #define P0004	000004
401 #define P0002	000002
402 #define P0001	000001
403 
404 #define	ON	1
405 #define OFF	0
406 
407 
408 predict(y, r, e)
409 register int y;
410 int e, r;
411 {
412 	unsigned int same = 0;
413 	unsigned register int mask = 0;
414 	unsigned register int state = 0;
415 	unsigned register int i;
416 	unsigned int prev = 0, new = 0, except = 0;
417 	extern unsigned int getmask();
418 
419 	i = r;
420 	do {
421 		state = except = prev = 0;
422 		mask = getmask(y);
423 		if(mask & P8192) {
424 			mask ^= 017777;
425 			prev = 1;
426 		}
427 		mask &= 017777;
428 		same = getdot(mask);
429 		if( i == 1 && e == 0) {	/* exception point */
430 			except = 1;
431 		}
432 		state = except;
433 		state |= prev << 1;
434 		state |= same << 2;
435 		switch(state & 07) {
436 			case 0:
437 			case 3:
438 			case 5:
439 			case 6:
440 				new = ON;
441 				break;
442 			case 1:
443 			case 2:
444 			case 4:
445 			case 7:
446 				new = OFF;
447 				break;
448 			default:
449 				error("Unexpected state %#o\n", state);
450 		}
451 		storedot( new, y );
452 		y++;
453 	} while (--i);
454 }
455 
456 /*
457  * find wether the dot should be the same or not
458  */
459 
460 #define PMASK	017774
461 #define TWOBIT	03
462 
463 
464 getdot(value)
465 unsigned int value;
466 {
467 	register int tmp, i, j, k;
468 
469 	i = (value & PMASK) >> 2;
470 	j = value & TWOBIT;
471 	if(i > sizeof(Ptable))
472 		error("Prom adressing error");
473 
474 	tmp = Ptable[i];
475 	k = (tmp >> j) & 1;
476 	return k;
477 }
478 
479 
480 /*
481  * store point in current working area
482  */
483 
484 storedot( dot, y)
485 register unsigned int dot;
486 register int y;
487 {
488 	if(y > Lmax + 2 + Y )
489 		error("Out of range in store dot, y = %d", y);
490 
491 	if(y == endline -1)
492 		return;
493 	sl0[y] = dot;
494 }
495 
496 
497 /*
498  * construct the predict mask for position x, y
499  */
500 
501 unsigned int
502 getmask(y)
503 register int y;
504 {
505 	register unsigned int mask = 0;
506 
507 	if( y < 3 || y > 1029)
508 		error("Out of range in getmask, y = %d\n", y);
509 
510 	if( sl3[y+2] )		/* PROM 1    */
511 		mask |= P0001;
512 	if( sl3[y+1] )
513 		mask |= P0002;
514 	if( sl3[y-1] )		/* PROM 4    */
515 		mask |= P0004;
516 	if( sl3[y-2] )		/* PROM 8    */
517 		mask |= P0008;
518 	if( sl2[y+3] )		/* PROM 16   */
519 		mask |= P0016;
520 	if( sl2[y+1] )		/* PROM 32   */
521 		mask |= P0032;
522 	if( sl2[y-1] )		/* PROM 64   */
523 		mask |= P0064;
524 	if( sl2[y-3] )		/* PROM 128  */
525 		mask |= P0128;
526 	if( sl1[y+2] )		/* PROM 256  */
527 		mask |= P0256;
528 	if( sl1[y+1] )		/* PROM 512  */
529 		mask |= P0512;
530 	if( sl1[ y ] )		/* PROM 1024 */
531 		mask |= P1024;
532 	if( sl1[y-1] )		/* PROM 2048 */
533 		mask |= P2048;
534 	if( sl1[y-3] )		/* PROM 4096 */
535 		mask |= P4096;
536 	if( sl0[y-1] )		/* PROM 8192 */
537 		mask |= P8192;
538 	return(mask);
539 }
540 
541 
542 /*
543  * swap the scan line buffers
544  */
545 
546 swapscanp()
547 {
548 	register Byte *sav;
549 
550 	/*
551 	 * swap the buffers
552 	 */
553 	sav = sl3;
554 	sl3 = sl2;
555 	sl2 = sl1;
556 	sl1 = sl0;
557 	sl0 = sav;
558 
559 }
560 
561 
562 cleanup()
563 {
564 	register int i;
565 	register int j;
566 
567 	for( i = 0; i < 1030; i++)
568 		a[i] = b[i] = c[i] = d[i] = 0;
569 	sl0 = &a[3];
570 	sl1 = &b[3];
571 	sl2 = &c[3];
572 	sl3 = &d[3];
573 	for( i = 0; i < MAXnat; i++)
574 		for( j = 0; j < MAXnat; j++) {
575 			newbitmap[j][i] = 0;
576 			sqmap[j][i] = 0;
577 			prmap[j][i] = 0;
578 			uline[j] = 0;
579 		}
580 	for( i = 0; i < MAXnat; i++)
581 		for (j = 0; j < MAX; j++)
582 			bitmap[j][i] = 0;
583 	eoc = 0;
584 	(void) fclose(fd);
585 }
586 
587 
588 /*
589  * store the curent scan line in the bitmap
590  *
591  * bit clumsy, we could just as well dump everyscan line each time
592  * but, as said before, we don't know what to do with the bitmap...
593  *
594  */
595 
596 storescanline(x, y, toy)
597 register int x, y, toy;
598 {
599 	register int m, n, i;
600 
601 	m = x / 8;
602 	n = x % 8;
603 	if(m > MAX)
604 		error("bit map overflow for x (%d)\n", m);
605 
606 	if(toy >= MAXnat)
607 		error("Bitmap overflow");
608 	for( i = y; i < toy; i++)
609 		if(sl0[i])
610 			bitmap[m][i] |= (1 << n);
611 }
612 
613 short width, height;
614 
615 #define For_v for(v=0; v < height; v++)
616 #define For_h for(h=0; h < width; h++)
617 
618 
619 /*
620  * print the bit map
621  */
622 
623 setbitmap(fromx, fromy, tox, toy)
624 int fromx, fromy, tox, toy;
625 {
626 	register int m, n;
627 	register int x, y;
628 	nat v, h;
629 
630 	width = tox - fromx;
631 	height = toy - fromy;
632 	if (width > MAXnat || height > MAXnat) {
633 		error("*** X or Y is too large (%d %d)\n", width, height);
634 	}
635 
636 	dbprintf("# Rectangle map of character %s\n", filename);
637 	dbprintf("%% X %d Y %d\n", width, height);
638 
639 	for(v= 0, y = toy - 1; y >= fromy; v++, y--) {
640 		for( h=0, x = fromx; x < tox; h++, x++) {
641 			m = x / 8;
642 			n = x % 8;
643 			if((bitmap[m][y]  >> n ) & 1)
644 				newbitmap[v][h] = 1;
645 			else
646 				newbitmap[v][h] = 0;
647 		}
648 	}
649 }
650 
651 
652 
653 maxsq()
654 {
655 	register nat v, h, m;
656 	nat uleft, up, left;
657 	For_h
658 		uline[h]= 0;
659 	For_v {
660 		uleft= left= 0;
661 		For_h {
662 			up= uline[h];
663 			if (newbitmap[v][h]) {
664 				m= uleft;
665 				if (up < m) m= up;
666 				if (left < m) m= left;
667 				sqmap[v][h]= ++m;
668 			} else
669 				sqmap[v][h]= m= 0;
670 			uleft= up;
671 			uline[h]= left= m;
672 		}
673 		sqmap[v][h]= 0;
674 	}
675 }
676 
677 
678 prune()
679 {
680 	register nat v, h, m;
681 	nat vv, hh;
682 	For_v {
683 		For_h {
684 			m= sqmap[v][h];
685 			for (vv= v; m && vv <= v+1 && vv < height; vv++)
686 			for (hh= h; m && hh <= h+1 && hh < width; hh++)
687 				if (sqmap[vv][hh] > m) m= 0;
688 			prmap[v][h]= m;
689 		}
690 	}
691 }
692 
693 
694 combi()
695 {
696 	register nat v, h, m, p=0, hh;
697 	int rects = 0;	/* track number of structures written */
698 
699 	For_v {
700 		p=m= 0;
701 		for (h= 0; h <= width; h++) {
702 			if (h == width || prmap[v][h] != m) {
703 				/* Don't pay attention to "singletons" (h-p == 1) */
704 				if (m && h-p > 1) {
705 					rects++;
706 					rect.yO = v-m+1;
707 					rect.y = m;
708 					rect.xO = p-m+1;
709 					rect.x = h-1-p+m;
710 					oput(rect);
711 					dbprintf("> V@%3d|%3d*H@%3d|%3d\n",  v-m+1, m, p-m+1, h-1-p+m);
712 					/* Mark squares as accounted for */
713 					for (hh= p; hh < h; hh++) sqmap[v][hh]= 0;
714 				}
715 				if (h < width) m= prmap[v][p= h];
716 			}
717 		}
718 	}
719 	for (h = 0; h <= width; h++) {
720 		p=m= 0;
721 		for (v= 0; v <= height; v++) {
722 			if (v == height || prmap[v][h] != m) {
723 				/* Pay attention to unaccounted-for "singletons" */
724 				if (m && (v-p > 1 || sqmap[v-1][h])) {
725 					rects++;
726 					rect.yO = p-m+1;
727 					rect.y = v-1-p+m;
728 					rect.xO = h-m+1;
729 					rect.x = m;
730 					oput(rect);
731 					dbprintf("> V@%3d|%3d*H@%3d|%3d\n", p-m+1, v-1-p+m, h-m+1, m);
732 				}
733 				if (v < height) m= prmap[p= v][h];
734 			}
735 		}
736 	}
737 	dbprintf("<\n");
738 	dbprintf("The Nstructs should be %d\n", rects);
739 	return(rects);
740 }
741 
742 headit()
743 {
744 	if(lseek(fdo, (long)0, 0) == -1)
745 		error("seek error in head routine");
746 	if(write(fdo, (char *) &head, sizeof(struct Header)) != sizeof(struct Header))
747 		error("write error in head routine");
748 }
749 setchars()
750 {
751 	if(lseek(fdo, (long)(sizeof(struct Header)), 0) == -1)
752 		error("seek error in setchars routine");
753 	if (write(fdo, (char *)Char, Charmax * sizeof(struct Chars)) != Charmax * sizeof(struct Chars))
754 		error("Write error in setchars routine");
755 }
756 
757 
758 /* output a rect struct */
759 
760 oput(r)
761 struct Rect r;
762 {
763 	*curp++ = r;
764 	if(curp > eob) {
765 		flusho();
766 		curp = bob;
767 	}
768 	offset += sizeof(struct Rect);
769 }
770 
771 /* flush the buffer holding the rectangles */
772 
773 flusho()
774 {
775 
776 	if ( write(fdo, (char *)bob, (int)(curp - bob) * sizeof(struct Rect)) !=
777 			(int)(curp - bob)*sizeof(struct Rect))
778 		error("Write error in flusho routine");
779 }
780 
781 setoffset()
782 {
783 	offset = sizeof(struct Header) + Charmax * sizeof(struct Chars);
784 }
785