Skip to content

Instantly share code, notes, and snippets.

@MurphyMc
Last active January 8, 2023 19:04
Show Gist options
  • Select an option

  • Save MurphyMc/7a5dfdd77d4a4cd267fc9eb1dfddd42d to your computer and use it in GitHub Desktop.

Select an option

Save MurphyMc/7a5dfdd77d4a4cd267fc9eb1dfddd42d to your computer and use it in GitHub Desktop.
rfbLoadConsoleFont() replacement for better Linux PSF console font file support in libvncserver
// rfbLoadConsoleFont()'s documentation says that it loads a Linux console
// font, but this is only kind of true. It's limited to loading 256 glyphs,
// which... okay. It's also limited to fonts which are 8x16, which many are.
// More annoyingly, however, it can't actually load from a PSF font file used
// by Linux console fonts, since it doesn't account for the header. In many
// cases, this means that just skipping the first four bytes would make it
// work (it would have been nice if there were just a parameter to tell it
// to do this, or if there was a version you could give a prepared FILE *).
// This function *does* actually load from a PSF file. It wouldn't be too
// hard to make it support v2, but it currently only supports v1 (however,
// the fonts I tried during testing were all v1). It only supports the
// first 256 glyphs even if there are more, and it ignores the Unicode and
// character mapping stuff (again, I got away with this on the fonts I
// tried since I am only immediately worried about ASCII support). It
// does, however, support fonts of different heights. It also supports
// reading from gzipped PSF files, which most of the ones installed by
// default on my system are.
// TLDR: This lets you load at least some normal Linux .psf console fonts
// for use with libvncserver if all you care about is ASCII.
rfbFontDataPtr load_psf_font (char * file)
{
int cmp = strlen(file) >= 3 && !strcmp(file+strlen(file)-3, ".gz");
int success = 0;
FILE * f = NULL;
gzFile gf = NULL;
rfbFontDataPtr font = NULL;
do
{
font = calloc(1, sizeof(*font));
if (!font) break;
int magic1, magic2, mode, charsize;
if (cmp)
{
gf = gzopen(file, "rb");
if (!gf) break;
magic1 = gzgetc(gf);
magic2 = gzgetc(gf);
mode = gzgetc(gf);
charsize = gzgetc(gf);
}
else
{
f = fopen(file, "rb");
if (!f) break;
magic1 = fgetc(f);
magic2 = fgetc(f);
mode = fgetc(f);
charsize = fgetc(f);
}
if (magic1 != 0x36 || magic2 != 0x04) break; // Not PSF v1
void * data = malloc(256*charsize);
int * meta = malloc(256*5*4);
font->data = data;
font->metaData = meta;
if (!data || !meta) break;
size_t sz;
if (cmp)
sz = gzfread(data, 256*charsize, 1, gf);
else
sz = fread(data, 256*charsize, 1, f);
if (sz != 1) break;
for (int i = 0; i < 256; ++i)
{
meta[i*5+0] = i*charsize;
meta[i*5+1] = 8; // PSF1 is always 8 pixels wide
meta[i*5+2] = charsize;
meta[i*5+3] = 0;
meta[i*5+4] = 0;
}
success = 1;
} while (0);
if (f) fclose(f);
if (gf) gzclose(gf);
if (success) return font;
rfbFreeFont(font);
return NULL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment