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;
}