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
main(argc,argv)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 *
gethuff(mcode)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
chardecode(huff,charno)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
huffdecode(huff)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
getnbits(n)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
getbit(init)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
predict(y,r,e)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
getdot(value)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
storedot(dot,y)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
getmask(y)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
swapscanp()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
cleanup()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
storescanline(x,y,toy)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
setbitmap(fromx,fromy,tox,toy)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
maxsq()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
prune()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
combi()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
headit()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 }
setchars()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
flusho()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
setoffset()781 setoffset()
782 {
783 offset = sizeof(struct Header) + Charmax * sizeof(struct Chars);
784 }
785