Last active
January 25, 2020 21:01
-
-
Save travisstaloch/b21cda9bc28b5c4eb147a6299245fb5a to your computer and use it in GitHub Desktop.
parse psf font file, getting the header at comptime
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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