TTF GLYF Work, and Wrapping malloc()

TTF Work

I’ve only had a bit of time to work on the DOS game lately, with Further Confusion over the weekend.

I did get a little done on the font loader, though. I’m now reading in Glyph outline data! This is super exciting. Soon It’ll be time to try to rasterize this stuff. Once I’ve got actual font data coming in, getting characters mapped to glyph data, and rendering, I’ll just need to go back and fill in other significant stuff like the different CMAP formats, figuring out character advance and kerning data, and others. Soon!

malloc() wrapper

I threw in a malloc() and free() wrapper because I know I’m going to need it. This is something I stumbled across in Ninkasi code. Some of the errors AFL found were due to truncated integers in malloc() calls. This is especially for arrays, where I might try to allocate some array like…

malloc(elementCount * sizeof(struct Something));

Keep in mind that Ninkasi is intended to work on 16-bit, 32-bit, and 64-bit machines, but uses 32-bit integers for everything internally (and has a 32-bit address space). What this meant was that arrays loaded from files could be larger than the maximum object size for a given platform.

On the real-mode DOS side, this meant size_t was 16-bits. malloc() takes a size_t as an argument. Passing 32-bit values into malloc() would get truncated to 16-bits without the program knowing (or the compiler giving a warning, grumblegrumble), and then the program happily writing off the end of the array regardless, because the number of bytes to read is still stored as that 32-bit value.

On the 32-bit side, we can still have an issue with this. because some 32-bit value times another 32-bit value can easily overflow without a warning, but leaving us with a truncated allocation.

So the solution is a malloc() wrapper that checks for an overflow. This is fairly simple…

// Note: nkuint32_t is our 32-bit unsigned int typedef, because we
// target platforms from before the existence of a proper 32-bit
// typedef.

void *mallocWrapper(nkuint32_t size)
{
    if(size > ~(size_t)0) {
        return NULL;
    }

    return malloc(size);
}

In fact, it’s so simple that the compiler will often vomit out a warning at you that the test is always going to fail, if you’re on a platform where size_t is 32-bits or greater. But at least this will protect the 16-bit build from impossible malloc() calls.

Now let’s see that array-allocation wrapper…

void *mallocArray(nkuint32_t count, nkuint32_t size)
{
    // FIXME: See if this overflow check really works.
    if(count >= ~(nkuint32_t)0 / size) {
        return NULL;
    }

    return mallocWrapper(count * size);
}

This one will protect us from truncating the allocation size when we have an impossible size and count combination.

Probably.

Actually, I need to verify that that overflow check works, but I’ll save that for another day.

Time to sleep!

TTF CMAP Cleanup

Spent a bit of time over the weekend cleaning up my CMAP loading code for TTF loader in my DOS game library. This is stuff that’s not particularly glamourous, even from the perspective of font graphics. All it’s doing right now is mapping characters to glyph indices. Haven’t even started on the glyph loading code itself.

There’s a hell of a lot in the TTF format, and I’m only implementing a subset of it, but I honestly wasn’t expecting to run into this kind of complexity before even getting to the glyph data. The character-to-glyph mapping stuff is hard.

There are about a dozen different ways to map characters to glyphs, and I’ve spent most of the time on this project (the font loader, not the DOS game overall) working on format 4. It stores a series of “segments” which refer to a range of characters, and each of those segments can map to a contiguous range of glyphs, OR they can just map to an array of character IDs hanging off at the end of the buffer. The offsets into that buffer are offsets from the point you’d be at in the file if you were looking at a specific index in the array corresponding to that character.

I get the impression that TTFs were just meant to be loaded into memory as-is and then to have all these character mapping shenanigans happen in-memory, with the way these offsets work. Of course, that doesn’t work out so great on little endian machines, because everything in the file is stored big endian. So no matter what way you slice it, there’s going to be some data massaging happening before you can really use it on little endian.

Anyway. Yikes. I didn’t know font loading was going to be quite this silly. But I’m still having fun, so… onwards!

Naga Skateboard Design

Naga Skateboard Design

So apparently a custom-printed skateboard costs only a little more than a not-custom-printed skateboard, so I decided to do a drawing for the bottom of the one I want to get, and I drew a naga.