Skip to content

Instantly share code, notes, and snippets.

@travisstaloch
Last active January 25, 2020 21:01
Show Gist options
  • Save travisstaloch/b21cda9bc28b5c4eb147a6299245fb5a to your computer and use it in GitHub Desktop.
Save travisstaloch/b21cda9bc28b5c4eb147a6299245fb5a to your computer and use it in GitHub Desktop.
parse psf font file, getting the header at comptime
const std = @import("std");
const warn = std.debug.warn;
test "parse psf font file" {
// https://github.com/monarrk/trOS/raw/master/src/vga/font.psf
// const font_raw = @embedFile("font.psf");
// https://github.com/powerline/fonts/blob/master/Terminus/PSF/ter-powerline-v16b.psf.gz
const font_raw = @embedFile("ter-powerline-v16b.psf");
const PSFHeader = extern struct {
magic: u32,
version: u32,
headersize: u32,
flags: u32,
numglyph: u32,
bytesPerGlyph: u32,
height: u32,
width: u32,
};
const hdr = comptime blk: {
var s = std.io.SliceInStream.init(font_raw);
var stream = &s.stream;
var _hdr: PSFHeader = undefined;
// const file = try std.fs.File.openRead("./font.psf");
// defer file.close();
// const stream = &file.inStream().stream;
inline for (std.meta.fields(PSFHeader)) |f| {
const n = stream.readIntLittle(f.field_type) catch |err| {
warn("err {}\n", .{err});
break;
};
@field(_hdr, f.name) = n;
}
break :blk _hdr;
};
warn("hdr {}\n", .{hdr});
var s = std.io.SliceSeekableInStream.init(font_raw);
var sstream = &s.seekable_stream;
var stream = &s.stream;
_ = try sstream.seekTo(@sizeOf(PSFHeader));
const GlyphRow = @IntType(false, hdr.width);
const Glyph = [hdr.height]GlyphRow;
var i: usize = 0;
var glyphs: [hdr.numglyph]Glyph = undefined;
for (glyphs) |*a| {
for (a) |*e|
e.* = stream.readIntLittle(GlyphRow) catch |err| {
warn("err {}\n", .{err});
break;
};
}
// i = 0;
// while (i < 10) : (i += 1) {
// for (glyphs[i]) |g| warn("{b:0>8}\n", .{g});
// warn("\n", .{});
// }
// checked against ter-powerline-v16b.psf. seems to be working
if (hdr.flags != 0) {
var glyphnum: u16 = 0;
var unicode = [1]u16{0} ** std.math.maxInt(u21);
while (true) {
const s0 = readByte(stream) catch break;
// warn("s0 {b:0>8} \n", .{s0});
if (s0 == 0xFF) {
glyphnum += 1;
continue;
} else {
var len = try std.unicode.utf8ByteSequenceLength(s0);
const uc = switch (len) {
1 => @as(u21, s0),
2 => try std.unicode.utf8Decode2(&[_]u8{
s0,
readByte(stream) catch break,
}),
3 => try std.unicode.utf8Decode3(&[_]u8{
s0,
readByte(stream) catch break,
readByte(stream) catch break,
}),
4 => try std.unicode.utf8Decode4(&[_]u8{
s0,
readByte(stream) catch break,
readByte(stream) catch break,
readByte(stream) catch break,
}),
else => break,
};
unicode[uc] = glyphnum;
// warn("unicode[{}] = {}\n", .{ uc, glyphnum });
}
}
}
}
fn readByte(stream: var) !u8 {
return stream.readByte() catch |err| {
warn("err {}\n", .{err});
return err;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment