grim@HUEY.UDEL.EDU (Dan Grim) (03/23/87)
Here are three programs that should help with QMS roms. The first one decodes a rom-format font and should pretty well document the rom-format as I understand it. The last two convert fonts in down-load format to rom-format. There is a separate program for portrait and landscape fonts. I am copying this message to laser-lovers because I responded to one other request for these programs with the wrong program! I apologize to the person that got that program since I don't remember who it was! ------------------------------ bits.c ---------------------------- #include <stdio.h> int checksum; main(argc,argv) int argc; char *argv[]; { FILE *f; unsigned char font_head[16]; unsigned short char_head[12]; char *filename; int code1,code2,curloc,i,j,h,hh,height,width,x,z; short scan_flag,verbose,hex; int characters,first,number; if (argc < 2) { printf("Usage: %s {-vhs} <file> {start loc}\n",argv[0]); printf(" This program lists the contents of a QMS"); printf(" Lasergrafix 1200 rom-based font.\n"); printf(" -v makes a very verbose listing with every"); printf(" byte of data decoded.\n"); printf(" -h makes a hex format file that can be reencoded"); printf(" with the 'rom' program.\n"); printf(" -s makes a scan for all of the fonts in a file.\n"); exit(1); } /* * Here are the defaults: */ verbose = 0; hex = 0; scan_flag = 0; curloc = 0; filename = (char *)0; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') switch(argv[i][1]) { case 'v': verbose = 1; break; case 'h': hex = 1; break; case 's': scan_flag = 1; break; default: printf("%s: bad switch: %s\n",argv[0],argv[i]); exit(1); } else if (filename == (char *)0) filename = argv[i]; else (void)sscanf(argv[i],"%o",&curloc); } if (verbose + hex + scan_flag > 1) { printf("%s: only one switch at a time please!\n"); exit(1); } if (filename == (char *)0) { printf("%s: no filename specified\n",argv[0]); exit(1); } if ((f = fopen(filename,"r")) == NULL) { printf("%s: can't read '%s'\n",argv[0],filename); exit(1); } if (curloc) (void)fseek(f,(long)curloc,0); /* * The first part of the font is a header of the form: * * struct font_header * { * char flag1; /* always hex f0 */ /* char flag2; /* always hex 0f */ /* char characters; /* number of characters in the font */ /* char format; /* font format, 0 = X, 1 = Y */ /* char number2; /* low order font number */ /* char name[4]; /* i.e. CORB, SRPD, CORI, etc. */ /* char version; /* version number in ASCII */ /* char zero[2]; /* two bytes of zero */ /* char basline; /* offset to the baseline */ /* char zero1; /* another byte of zero */ /* char number1; /* high order font number */ /* char checksum; /* sum of other 15 bytes of header */ /* }; */ first = 1; again: for (i = 0; i < 16; i++) font_head[i] = fgetc(f); if (font_head[0] != 0xf0 || font_head[1] != 0x0f) { if (!first) { printf("End of File!\n"); exit(0); } printf("%s: Bad marker at start of font: %02x %02x\n", argv[0],font_head[0],font_head[1]); exit(1); } if (font_head[3] != 0 && font_head[3] != 1) { printf("%s: This font is in the wrong format!\n",argv[0]); exit(1); } characters = font_head[2]; number = font_head[14] * 256 + font_head[4]; if (!hex) printf("%06o/ ",curloc); for (i = 0; i < 16; i++) printf("%02x ",font_head[i]); curloc += 16; if (!hex) { if (font_head[10] != 0 || font_head[11] != 0 || font_head[13] != 0) printf("\n%s: Warning: some zero bytes are non zero ",argv[0]); checksum = 0; for (i = 0; i < 15; i++) checksum += font_head[i]; checksum &= 0xff; printf("Checksum: %02x %s\n",checksum, font_head[15] == checksum ? "[ok]" : "[mismatch]"); } if (verbose || scan_flag) { printf("\nFont Header Contents:\n\n"); printf(" Number of characters: %d\n",characters); printf(" Font format: %d: ",font_head[3]); if (font_head[3] == 0) printf("X orientation, P for 800, L for 1200\n"); else if (font_head[3] == 1) printf("Y orientation, P for 1200, L for 800\n"); else printf("Unknown orientation\n"); printf(" Font number: %d\n",number); printf(" Font name: %.4s\n",font_head+5); printf(" Font version: %c\n",font_head[9]); printf(" Font baseline offset: %d\n\n",font_head[12]); } if (hex) printf("\n"); checksum = 0; while (feof(f) == 0 && characters-- > 0) { /* * There is a header for each character which has the form: * * struct char_header * { * short zero; /* always zero */ /* short width1; /* char width in pixels */ /* short width2; /* same, may be different if a char */ /* /* had multiple bit maps but this */ /* /* never happens in ROM because a */ /* /* bit map can be arbitrarily large */ /* short height; /* char height in pixels */ /* short area1; /* high order char area, see below */ /* short area2; /* low order char area, see below */ /* short ascii; /* characters ASCII code */ /* short below; /* empty rows below bit map + 8000 */ /* short left; /* empty columns at left of bit map */ /* short bheight; /* bit map height in pixels */ /* short cols1; /* high order columns in bit map */ /* short cols2; /* low order columns in bit map */ /* }; * * The area information is encoded using a scheme which is * explained by looking at the code below. The reason for * the encoding escapes me but seems consistent in all of * the ROMs I've examined. * * The column width encoding is demonstrated by the 'cols' * subroutine below. The encoding depends also on the height * of the character in 16-bit words. */ if (!hex && !scan_flag) printf("%06o/ ",curloc); for (i = 0; i < 12; i++) { char_head[i] = nexti(f); if (!scan_flag) printf("%04x ",char_head[i]); } curloc += 24; width = char_head[2]; height = char_head[9]; h = (height + 15) / 16; hh = (char_head[3] + 15) / 16; code1 = char_head[10]; code2 = char_head[11]; x = 0; if (hh & 1 && width & 1) { z = 0x299 - hh * width; while (z < 0x25a) { x++; z += 0x40; } } else { z = 0x1d0 - hh * width; while (z < 0x191) { x++; z += 0x40; } } if (!hex && (x != char_head[4] || z != char_head[5])) printf(" *** %x %3x",x,z); z = cols(h,code1,code2); if (verbose) { printf("\n\nCharacter Header Contents:\n\n"); printf(" ASCII character code: %d (%o)\n", char_head[6],char_head[6]); if (font_head[3] == 0) { printf(" Character width: %d\n",char_head[0]); printf(" Character height: %d\n",width); printf(" Horizontal offset: %d\n",char_head[7]&0x7fff); printf(" Vertical offset: %d\n",char_head[8]); } else { printf(" Character width: %d\n",width); printf(" Character height: %d\n",char_head[3]); printf(" Vertical offset: %d\n",char_head[7]&0x7fff); printf(" Horizontal offset: %d\n",char_head[8]); } printf(" Bit map columns: %d\n",height); printf(" Bit map rows: %d\n",z); } while (feof(f) == 0) { if (z-- == 0) break; if (hex) printf("\n"); else if (verbose) printf("\n%06o/ ",curloc); for (i = 0; i < h; i++) { curloc += 2; j = nexti(f); if (hex) printf("%04x",j); else if (verbose) print_bin(j); } } j = nexti(f); if (!hex && j) printf("\n%06o/ %04x is not zero",curloc,j); curloc += 2; if (hex) printf("\n0000"); if (scan_flag) ; else if (hex || !verbose) printf("\n"); else printf("\n\n"); } j = nexti(f); checksum -= ((j >> 8) & 0xff) + (j & 0xff); checksum &= 0xffff; if (hex) printf("%04x\n",j); else printf("%06o/ %04x Checksum: %04x %s\n",curloc,j, checksum,j == checksum ? "[ok]" : "[mismatch]"); curloc += 2; if (scan_flag) { printf("\n"); first = 0; goto again; } } nexti(f) FILE *f; { int t; t = fgetc(f); t = (t << 8) + fgetc(f); checksum += (t & 0xff) + ((t >>8) & 0xff); return t; } print_bin(i) int i; { int j; for (j = 15; j >= 0; j--) (void)fputc(((i >> j) & 1) ? '*' : ' ',stdout); } cols(w,x,c) int w,x,c; { if (c > 0x40) { c -= x * 0x40; return (0x109 - c) / w; } else { c -= x * 0x40; return (0x40 - c) / w; } } ------------------------------ roml.c ---------------------------- #include <stdio.h> #include <ctype.h> #define FONT_DIR "/usr/local/fonts/canon" /* * This program reads a Lasergrafix 1200 font definition * in download format and writes a file suitable for * storing in a ROM. */ int checksum; /* For accumulating ROM checksum */ int space; /* Flag which determines where spaces */ /* go in the hex encoded output file */ main(argc,argv) int argc; char *argv[]; { FILE *fi,*fo; char filename[50]; char name[4],version; register int i,j,char_count; int c,h1,h2,k; int aa,bbb,ddd,eee,hhh,www,xxx,yyy; int eight_bit,number; if (argc != 4) { printf("Usage: %s <number> <font file> <rom file>\n", argv[0]); exit(1); } number = atoi(argv[1]); if (number < 1 || number > 32767) { printf("%s: font number (%d) out of range!\n", argv[0],number); exit(1); } if ((fi = fopen(argv[2],"r")) == NULL) { (void)sprintf(filename,"%s/%s",FONT_DIR,argv[2]); if ((fi = fopen(filename,"r")) == NULL) { printf("%s: can't read '%s'\n",argv[0],argv[2]); exit(1); } } if ((fo = fopen(argv[3],"w")) == NULL) { printf("%s: can't write '%s'\n",argv[0],argv[3]); exit(1); } eight_bit = 0; c = getc(fi); while (c == 'E' || c == 'S' || c == 'X' || c == 'Y') { if (c == 'E') eight_bit = getc(fi) - '0'; while ((c = getc(fi)) != '\n' && c != EOF) ; c = getc(fi); } if (c != 'L') { printf("%s: this only works for landscape fonts!\n",argv[0]); exit(1); } version = getc(fi); for (i = 0; i < 4; i++) name[i] = getc(fi); hhh = intin(fi,3); bbb = 0; if (isdigit(i = getc(fi))) { (void)ungetc(i,fi); bbb = intin(fi,3); i = getc(fi); } if (i != ',') { if (i == 'T') printf("%s: can't handle version 2 fonts!\n", argv[0]); else printf("%s: comma missing after glyph height - '%c'!\n", argv[0],i); exit(1); } if (!eight_bit && (i = getc(fi)) != '\n') { printf("%s: newline missing after glyph height - '%c'!\n", argv[0],i); exit(1); } char_count = 0; checksum = 0; (void)fseek(fo,48L,0); aa = 0; while (1) { h1 = hexin(fi); h2 = hexin(fi); if (h1 == -1 || h2 == -1) { printf("%s: non hex digit in char code, last good char %x\n", argv[0],aa); exit(1); } aa = (h1 << 4) + h2; www = intin(fi,3); yyy = intin(fi,3); xxx = intin(fi,3); ddd = intin(fi,3); eee = intin(fi,3); char_count++; space = 0; put_int(www,fo); put_int(0,fo); put_int(hhh,fo); put_int(www,fo); j = area(www,hhh,&k); put_int(k,fo); put_int(j,fo); put_int(aa,fo); put_int(0x8000+eee,fo); put_int(ddd,fo); put_int(xxx,fo); j = codeword(xxx,yyy,&k); put_int(k,fo); put_int(j,fo); (void)fputc('\n',fo); j = 2 * ((xxx + 15) / 16); while (yyy--) { for (i = 0; i < j; i++) { space = 0; if (eight_bit) put_byte(fgetc(fi),fo); else { h1 = hexin(fi); h2 = hexin(fi); if (h1 == -1 || h2 == -1) { printf("%s: bad hex code in character %2x!\n", argv[0],aa); exit(1); } put_byte((h1 << 4) + h2,fo); } } (void)fputc('\n',fo); } space = 0; put_int(0,fo); (void)fputc('\n',fo); i = getc(fi); if ((!eight_bit && i == '\n') || (eight_bit && i == '^')) break; if (i != ',') { printf("%s: comma missing after char %2x bitmap!\n", argv[0],aa); exit(1); } if (!eight_bit && getc(fi) != '\n') { printf("%s: newline missing after char %2x bitmap!\n", argv[0],aa); exit(1); } } space = 0; put_int(checksum,fo); (void)fputc('\n',fo); (void)fseek(fo,0L,0); checksum = 0; space = 0; put_byte(0xf0,fo); /* Beginning of font markers */ put_byte(0x0f,fo); /* ...more of the same */ put_byte(char_count,fo); /* Number of chars in the font */ put_byte(0,fo); /* Format version number = 0 */ put_byte(number,fo); /* Low order font number */ for (i = 0; i < 4; i++) put_byte(name[i],fo); /* Font name */ put_byte(version,fo); /* Font version */ put_byte(0,fo); /* Must be zero */ put_byte(0,fo); /* Must be zero */ put_byte(bbb,fo); /* Baseline offset */ put_byte(0,fo); /* Must be zero */ put_byte(number >> 8,fo); /* High order font number */ put_byte(checksum,fo); /* Header checksum */ (void)fputc('\n',fo); (void)fclose(fi); (void)fclose(fo); exit(0); } char hex[] = {"0123456789ABCDEF"}; put_byte(b,f) int b; FILE *f; { b &= 0xff; checksum += b; if (space == 0) space = 1; else (void)fputc(' ',f); (void)fputc(hex[(b >> 4) & 0xf],f); (void)fputc(hex[b & 0xf],f); } put_int(i,f) int i; FILE *f; { put_byte(i >> 8,f); space = 0; put_byte(i,f); } intin(f,k) FILE *f; register int k; { register int c,i; i = 0; while (k--) { c = getc(f); if (c < '0' || c > '9') { printf("bad number in 'intin'\n"); exit(1); } i = i * 10 + c - '0'; } return i; } hexin(f) FILE *f; { register int c; c = getc(f); while (c == '\n') c = getc(f); if ('0' <= c && c <= '9') c -= '0'; else if ('A' <= c && c <= 'F') c -= 'A' - 10; else if ('a' <= c && c <= 'f') c -= 'a' - 10; else c = -1; return c; } codeword(w,o,x) register int w,o; register int *x; { register int c; w = (w + 15) / 16; *x = 0; if (w & 1 && o & 1) { c = 0x109 - w * o; while (c <= 0xc6) { c += 0x40; (*x)++; } } else { c = 0x40 - w * o; while (c < 1) { c += 0x40; (*x)++; } } return c; } area(i,j,k) register int i,j; register int *k; { register int l; i = (i + 15) / 16; *k = 0; if (i & 1 && j & 1) { l = 0x299 - i * j; while (l < 0x25a) { l += 0x40; (*k)++; } } else { l = 0x1d0 - i * j; while (l < 0x191) { l += 0x40; (*k)++; } } return l; } ------------------------------ romp.c ---------------------------- #include <stdio.h> #include <ctype.h> #define FONT_DIR "/usr/local/fonts/raven" /* * This program reads a Lasergrafix 1200 font definition * in download format and writes a file suitable for * storing in a ROM. */ int checksum; /* For accumulating ROM checksum */ int space; /* Flag which determines where spaces */ /* go in the hex encoded output file */ main(argc,argv) int argc; char *argv[]; { FILE *fi,*fo; char filename[50]; char name[4],version; register int i,j,char_count; int c,h1,h2,k; int baseline,char_cd,eight_bit,glyph_ht,glyph_wd,number; int map_ht,map_wd,off_ht,off_wd; if (argc != 4) { printf("Usage: %s <number> <font file> <rom file>\n", argv[0]); exit(1); } number = atoi(argv[1]); if (number < 1 || number > 32767) { printf("%s: font number (%d) out of range!\n", argv[0],number); exit(1); } if ((fi = fopen(argv[2],"r")) == NULL) { (void)sprintf(filename,"%s/%s",FONT_DIR,argv[2]); if ((fi = fopen(filename,"r")) == NULL) { printf("%s: can't read '%s'\n",argv[0],argv[2]); exit(1); } } if ((fo = fopen(argv[3],"w")) == NULL) { printf("%s: can't write '%s'\n",argv[0],argv[3]); exit(1); } eight_bit = 0; c = getc(fi); while (c == 'E' || c == 'S' || c == 'X' || c == 'Y') { if (c == 'E') eight_bit = getc(fi) - '0'; while ((c = getc(fi)) != '\n' && c != EOF) ; c = getc(fi); } if (c != 'P') { printf("%s: this only works for portrait fonts!\n", argv[0]); exit(1); } version = getc(fi); for (i = 0; i < 4; i++) name[i] = getc(fi); glyph_ht = intin(fi,3); baseline = 0; if (isdigit(i = getc(fi))) { (void)ungetc(i,fi); baseline = intin(fi,3); i = getc(fi); } if (i != ',') { if (i == 'T') printf("%s: can't handle version 2 fonts!\n", argv[0]); else printf("%s: comma missing after glyph height - '%c'!\n", argv[0],i); exit(1); } if (!eight_bit && (i = getc(fi)) != '\n') { printf("%s: newline missing after glyph height - '%c'!\n", argv[0],i); exit(1); } char_count = 0; checksum = 0; (void)fseek(fo,48L,0); while (1) { h1 = hexin(fi); h2 = hexin(fi); if (h1 == -1 || h2 == -1) { printf("%s: non hex digit in char code\n",argv[0]); exit(1); } char_cd = (h1 << 4) + h2; glyph_wd = intin(fi,3); map_wd = intin(fi,3); map_ht = intin(fi,3); off_wd = intin(fi,3); off_ht = intin(fi,3); char_count++; space = 0; put_int(0,fo); put_int(glyph_wd,fo); put_int(glyph_wd,fo); put_int(glyph_ht,fo); j = area(glyph_ht,glyph_wd,&k); put_int(k,fo); put_int(j,fo); put_int(char_cd,fo); put_int(0x8000+off_ht,fo); put_int(off_wd,fo); put_int(map_ht,fo); j = codeword(map_ht,map_wd,&k); put_int(k,fo); put_int(j,fo); (void)fputc('\n',fo); j = 2 * ((map_ht + 15) / 16); while (map_wd--) { for (i = 0; i < j; i++) { space = 0; if (eight_bit) put_byte(fgetc(fi),fo); else { h1 = hexin(fi); h2 = hexin(fi); if (h1 == -1 || h2 == -1) { printf("%s: bad hex code in character %2x!\n", argv[0],char_cd); exit(1); } put_byte((h1 << 4) + h2,fo); } } (void)fputc('\n',fo); } space = 0; put_int(0,fo); (void)fputc('\n',fo); i = getc(fi); if ((!eight_bit && i == '\n') || (eight_bit && i == '^')) break; if (i != ',') { printf("%s: comma missing after char %2x bitmap!\n", argv[0],char_cd); exit(1); } if (!eight_bit && getc(fi) != '\n') { printf("%s: newline missing after char %2x bitmap!\n", argv[0],char_cd); exit(1); } } space = 0; put_int(checksum,fo); (void)fputc('\n',fo); (void)fseek(fo,0L,0); checksum = 0; space = 0; put_byte(0xf0,fo); /* Beginning of font markers */ put_byte(0x0f,fo); /* ...more of the same */ put_byte(char_count,fo); /* Number of chars in the font */ put_byte(1,fo); /* Format version number = 1 */ put_byte(number,fo); /* Low order font number */ for (i = 0; i < 4; i++) put_byte(name[i],fo); /* Font name */ put_byte(version,fo); /* Font version */ put_byte(0,fo); /* Must be zero */ put_byte(0,fo); /* Must be zero */ put_byte(baseline,fo); /* Baseline offset */ put_byte(0,fo); /* Must be zero */ put_byte(number >> 8,fo); /* High order font number */ put_byte(checksum,fo); /* Header checksum */ (void)fputc('\n',fo); (void)fclose(fi); (void)fclose(fo); exit(0); } char hex[] = {"0123456789ABCDEF"}; put_byte(b,f) int b; FILE *f; { b &= 0xff; checksum += b; if (space == 0) space = 1; else (void)fputc(' ',f); (void)fputc(hex[(b >> 4) & 0xf],f); (void)fputc(hex[b & 0xf],f); } put_int(i,f) int i; FILE *f; { put_byte(i >> 8,f); space = 0; put_byte(i,f); } intin(f,k) FILE *f; register int k; { register int c,i; i = 0; while (k--) { c = getc(f); if (c < '0' || c > '9') { printf("bad number in 'intin'\n"); exit(1); } i = i * 10 + c - '0'; } return i; } hexin(f) FILE *f; { register int c; c = getc(f); while (c == '\n') c = getc(f); if ('0' <= c && c <= '9') c -= '0'; else if ('A' <= c && c <= 'F') c -= 'A' - 10; else if ('a' <= c && c <= 'f') c -= 'a' - 10; else c = -1; return c; } codeword(w,o,x) register int w,o; register int *x; { register int c; w = (w + 15) / 16; *x = 0; if (w & 1 && o & 1) { c = 0x109 - w * o; while (c <= 0xc4) { c += 0x40; (*x)++; } } else { c = 0x40 - w * o; while (c < 1) { c += 0x40; (*x)++; } } return c; } area(i,j,k) register int i,j; register int *k; { register int l; i = (i + 15) / 16; *k = 0; if (i & 1 && j & 1) { l = 0x299 - i * j; while (l < 0x25a) { l += 0x40; (*k)++; } } else { l = 0x1d0 - i * j; while (l < 0x191) { l += 0x40; (*k)++; } } return l; }