summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2019-08-25 13:21:48 -0400
committerJune McEnroe <june@causal.agency>2019-08-25 13:21:48 -0400
commit4a54edfcd4b964a94b7c7f4fb7a8d30dd2272b7f (patch)
treeb5a8455f75f1763fa08f781272689860c2a4da4d
parentMark card functions inline (diff)
downloadwep-4a54edfcd4b964a94b7c7f4fb7a8d30dd2272b7f.tar.gz
wep-4a54edfcd4b964a94b7c7f4fb7a8d30dd2272b7f.zip
Remove files from cards repo
-rw-r--r--cards.3217
-rw-r--r--cards.c428
-rw-r--r--cards.h80
-rw-r--r--dump.148
-rw-r--r--dump.c82
-rw-r--r--exefmt.txt593
6 files changed, 0 insertions, 1448 deletions
diff --git a/cards.3 b/cards.3
deleted file mode 100644
index 7882756..0000000
--- a/cards.3
+++ /dev/null
@@ -1,217 +0,0 @@
-.Dd March 28, 2019
-.Dt CARDS 3
-.Os
-.
-.Sh NAME
-.Nm Cards_LoadCards ,
-.Nm Cards_LoadFreeCell ,
-.Nm Cards_InvertSurface
-.Nd bitmap resource loader
-.
-.Sh SYNOPSIS
-.In cards.h
-.
-.Ft int
-.Fo Cards_LoadCards
-.Fa "SDL_Surface *surfaces[]"
-.Fa "size_t count"
-.Fa "SDL_RWops *rw"
-.Fa "enum Cards_Flag flags"
-.Fc
-.
-.Ft int
-.Fo Cards_LoadFreeCell
-.Fa "SDL_Surface *surfaces[]"
-.Fa "size_t count"
-.Fa "SDL_RWops *rw"
-.Fa "enum Cards_Flag flags"
-.Fc
-.
-.Ft int
-.Fn Cards_InvertSurface "SDL_Surface *surface"
-.
-.Sh DESCRIPTION
-.Fn Cards_LoadCards
-and
-.Fn Cards_LoadFreeCell
-load bitmap resources
-into an array of
-.Fa count
-surfaces.
-Resources can be loaded
-from 16-bit NE executables
-or from 32-bit PE executables.
-.
-.Pp
-.Fn Cards_LoadCards
-loads card bitmaps from a
-.Pa CARDS.DLL
-or Windows 3.0
-.Pa SOL.EXE
-file
-.Fa rw .
-.
-.Pp
-Indices of loaded surfaces
-are defined by the following:
-.Bl -tag -width Ds -offset indent
-.It Suit
-.Dv Cards_Club ,
-.Dv Cards_Diamond ,
-.Dv Cards_Heart ,
-.Dv Cards_Spade .
-.It Rank
-.Dv Cards_A ,
-.Dv Cards_2 ,
-.Dv Cards_3 ,
-.Dv Cards_4 ,
-.Dv Cards_5 ,
-.Dv Cards_6 ,
-.Dv Cards_7 ,
-.Dv Cards_8 ,
-.Dv Cards_9 ,
-.Dv Cards_10 ,
-.Dv Cards_J ,
-.Dv Cards_Q ,
-.Dv Cards_K .
-.It Back
-.Dv Cards_Back1 ,
-.Dv Cards_Back2 ,
-.Dv Cards_Back3 ,
-.Dv Cards_Back4 ,
-.Dv Cards_Back5 ,
-.Dv Cards_Back6 ,
-.Dv Cards_Back7 ,
-.Dv Cards_Back8 ,
-.Dv Cards_Back9 ,
-.Dv Cards_Back10 ,
-.Dv Cards_Back11 ,
-.Dv Cards_Back12 .
-.It Other
-.Dv Cards_Empty ,
-.Dv Cards_X ,
-.Dv Cards_O .
-.El
-.
-.Pp
-Where suit and rank constants
-are added together to form an index.
-Note that there are gaps in the indices
-and some surface pointers will be set to
-.Dv NULL .
-The maximum number of surfaces
-is defined by
-.Dv Cards_CardCount .
-.
-.Pp
-The dimensions of the loaded surfaces
-are defined by
-.Dv Cards_CardWidth
-and
-.Dv Cards_CardHeight .
-.
-.Pp
-.Fn Cards_LoadCards
-accepts the following flags:
-.Bl -tag -width "Cards_BlackBorders" -offset indent
-.It Dv Cards_ColorKey
-Use color key transparency for the
-.Dv Cards_Empty ,
-.Dv Cards_X
-and
-.Dv Cards_O
-surfaces.
-.It Dv Cards_AlphaCorners
-Make the rounded card corners transparent.
-.It Dv Cards_BlackBorders
-Make all card borders black.
-.El
-.
-.Pp
-.Fn Cards_LoadFreeCell
-loads bitmaps from a
-.Pa FREECELL.EXE
-file
-.Fa rw .
-.
-.Pp
-Indices of loaded surfaces
-are defined by
-.Dv Cards_KingRight ,
-.Dv Cards_KingLeft
-and
-.Dv Cards_KingWin .
-Note that there are gaps in the indices
-and some surface pointers will be set to
-.Dv NULL .
-The maximum number of surfaces
-is defined by
-.Dv Cards_FreeCellCount .
-.
-.Pp
-The dimensions of the loaded surfaces
-are defined by
-.Dv Cards_KingWidth
-and
-.Dv Cards_KingHeight .
-.
-.Pp
-.Fn Cards_LoadFreeCell
-accepts the following flags:
-.Bl -tag -width "Cards_ColorKey" -offset indent
-.It Dv Cards_ColorKey
-Use color key transparency.
-.El
-.
-.Pp
-.Fn Cards_InvertSurface
-inverts the colors of a surface loaded by
-.Fn Cards_LoadCards .
-.
-.Sh RETURN VALUES
-Upon successful completion,
-the value 0 is returned;
-otherwise the value -1 is returned.
-.
-.Sh ERRORS
-Error messages are set with
-.Fn SDL_SetError
-and can be retrieved with
-.Fn SDL_GetError .
-.
-.Pp
-.Fn Cards_LoadCards
-and
-.Fn Cards_LoadFreeCell
-may fail for the following reasons:
-any
-.Vt SDL_RWops
-or
-.Vt SDL_Surface
-error;
-invalid MZ, NE or PE signatures;
-missing resource table;
-invalid resource hierarchy;
-missing resource.
-.
-.Pp
-.Fn Cards_InvertSurface
-may fail for any
-.Vt SDL_Surface
-error
-or if the surface format is not supported.
-.
-.Sh STANDARDS
-.Bl -item
-.It
-The New Executable format,
-documented in
-.Pa exefmt.txt .
-.It
-The Portable Executable format,
-documented at
-.Lk https://docs.microsoft.com/en-us/windows/desktop/Debug/pe-format .
-.El
-.
-.Sh AUTHORS
-.An C. McEnroe Aq Mt june@causal.agency
diff --git a/cards.c b/cards.c
deleted file mode 100644
index ddc5b86..0000000
--- a/cards.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "cards.h"
-
-static SDL_Surface *
-dibSurface(SDL_RWops *rw, Uint32 offset, Uint32 length) {
-	Uint32 bitmapLength = 0x0E + length;
-
-	Uint8 *buffer = malloc(bitmapLength);
-	if (!buffer) {
-		SDL_SetError("malloc error: %s", strerror(errno));
-		return NULL;
-	}
-
-	SDL_RWops *bitmap = SDL_RWFromMem(buffer, bitmapLength);
-	if (!bitmap) {
-		free(buffer);
-		return NULL;
-	}
-
-	if (SDL_RWseek(rw, offset, RW_SEEK_SET) < 0) goto fail;
-	Uint32 dibHeaderLength = SDL_ReadLE32(rw);
-	Uint32 bitmapDataOffset = 0x0E + dibHeaderLength;
-
-	if (dibHeaderLength == 0x0C) {
-		if (SDL_RWseek(rw, 0x06, RW_SEEK_CUR) < 0) goto fail;
-		Uint16 bitsPerPixel = SDL_ReadLE16(rw);
-		bitmapDataOffset += 3 * (1 << bitsPerPixel);
-
-	} else if (dibHeaderLength == 0x28) {
-		if (SDL_RWseek(rw, 0x0A, RW_SEEK_CUR) < 0) goto fail;
-		Uint16 bitsPerPixel = SDL_ReadLE16(rw);
-		if (SDL_RWseek(rw, 0x10, RW_SEEK_CUR) < 0) goto fail;
-		Uint32 paletteLength = SDL_ReadLE32(rw);
-
-		if (!paletteLength && bitsPerPixel < 16) {
-			paletteLength = 1 << bitsPerPixel;
-		}
-		bitmapDataOffset += 4 * paletteLength;
-
-	} else {
-		SDL_SetError("unrecognized DIB header length %u", dibHeaderLength);
-		goto fail;
-	}
-
-	SDL_WriteU8(bitmap, 'B');
-	SDL_WriteU8(bitmap, 'M');
-	SDL_WriteLE32(bitmap, bitmapLength);
-	SDL_WriteLE16(bitmap, 0); // reserved
-	SDL_WriteLE16(bitmap, 0); // reserved
-	SDL_WriteLE32(bitmap, bitmapDataOffset);
-
-	if (SDL_RWseek(rw, offset, RW_SEEK_SET) < 0) goto fail;
-	if (SDL_RWread(rw, &buffer[SDL_RWtell(bitmap)], length, 1) < 1) goto fail;
-
-	SDL_RWseek(bitmap, 0, RW_SEEK_SET);
-	SDL_Surface *surface = SDL_LoadBMP_RW(bitmap, 1);
-	free(buffer);
-	return surface;
-
-fail:
-	SDL_RWclose(bitmap);
-	free(buffer);
-	return NULL;
-}
-
-// exefmt.txt
-static int
-loadNE(
-	SDL_Surface **surfaces, size_t count,
-	SDL_RWops *rw, Uint16 neOffset, Uint32 idSkip
-) {
-	if (SDL_RWseek(rw, neOffset + 0x24, RW_SEEK_SET) < 0) return -1;
-	Uint16 resourceTableOffset = neOffset + SDL_ReadLE16(rw);
-
-	if (SDL_RWseek(rw, resourceTableOffset, RW_SEEK_SET) < 0) return -1;
-	Uint16 alignmentShift = SDL_ReadLE16(rw);
-
-	Uint16 resourceCount;
-	for (;;) {
-		Uint16 typeID = SDL_ReadLE16(rw);
-		resourceCount = SDL_ReadLE16(rw);
-		SDL_ReadLE32(rw); // reserved
-
-		if (!typeID) {
-			SDL_SetError("no bitmap resources");
-			return -1;
-		}
-		if (typeID == 0x8002) break;
-
-		if (SDL_RWseek(rw, 0x0C * resourceCount, RW_SEEK_CUR) < 0) return -1;
-	}
-
-	for (Uint16 i = 0; i < resourceCount; ++i) {
-		Uint16 dataOffset = SDL_ReadLE16(rw);
-		Uint16 dataLength = SDL_ReadLE16(rw);
-		/* Uint16 flags = */ SDL_ReadLE16(rw);
-		Uint16 resourceID = SDL_ReadLE16(rw);
-		SDL_ReadLE32(rw); // reserved
-
-		resourceID &= 0x7FFF;
-		if (resourceID >= idSkip) resourceID -= idSkip;
-		if (resourceID >= count) continue;
-
-		Sint64 nextResource = SDL_RWtell(rw);
-		if (nextResource < 0) return -1;
-
-		surfaces[resourceID] = dibSurface(
-			rw,
-			(Uint32)dataOffset << alignmentShift,
-			(Uint32)dataLength << alignmentShift
-		);
-		if (!surfaces[resourceID]) return -1;
-
-		if (SDL_RWseek(rw, nextResource, RW_SEEK_SET) < 0) return -1;
-	}
-
-	return 0;
-}
-
-// <https://docs.microsoft.com/en-us/windows/desktop/Debug/pe-format>
-static int
-loadPE(
-	SDL_Surface **surfaces, size_t count,
-	SDL_RWops *rw, Uint16 peOffset, Uint32 idSkip
-) {
-	if (SDL_RWseek(rw, peOffset + 0x04 + 0x02, RW_SEEK_SET) < 0) return -1;
-	Uint16 sectionCount = SDL_ReadLE16(rw);
-
-	if (SDL_RWseek(rw, peOffset + 0x04 + 0x10, RW_SEEK_SET) < 0) return -1;
-	Uint16 optionalHeaderLength = SDL_ReadLE16(rw);
-	Uint16 sectionTableOffset = peOffset + 0x04 + 0x14 + optionalHeaderLength;
-
-	Uint32 resourceTableOffset = 0;
-	Uint32 resourceTableVirtual = 0;
-	for (Uint16 i = 0; i < sectionCount; ++i) {
-		Uint16 headerOffset = sectionTableOffset + 0x28 * i;
-
-		if (SDL_RWseek(rw, headerOffset, RW_SEEK_SET) < 0) return -1;
-		char name[8];
-		if (!SDL_RWread(rw, name, sizeof(name), 1)) return -1;
-		if (strncmp(".rsrc", name, sizeof(name))) continue;
-
-		if (SDL_RWseek(rw, headerOffset + 0x0C, RW_SEEK_SET) < 0) return -1;
-		resourceTableVirtual = SDL_ReadLE32(rw);
-
-		if (SDL_RWseek(rw, headerOffset + 0x14, RW_SEEK_SET) < 0) return -1;
-		resourceTableOffset = SDL_ReadLE32(rw);
-
-		break;
-	}
-	if (!resourceTableOffset) {
-		SDL_SetError("no resource table");
-		return -1;
-	}
-
-	if (SDL_RWseek(rw, resourceTableOffset + 0x0C, RW_SEEK_SET) < 0) return -1;
-	Uint16 typeNameCount = SDL_ReadLE16(rw);
-	Uint16 typeIDCount = SDL_ReadLE16(rw);
-
-	if (SDL_RWseek(rw, 0x08 * typeNameCount, RW_SEEK_CUR) < 0) return -1;
-
-	Uint32 bitmapTableOffset = 0;
-	for (Uint16 i = 0; i < typeIDCount; ++i) {
-		Uint32 typeID = SDL_ReadLE32(rw);
-		Uint32 subdirOffset = SDL_ReadLE32(rw);
-		if (typeID != 0x02) continue;
-		if (!(subdirOffset & (1 << 31))) {
-			SDL_SetError("bitmap type entry does not point to table");
-			return -1;
-		}
-		bitmapTableOffset = resourceTableOffset + (subdirOffset & ~(1 << 31));
-		break;
-	}
-
-	if (SDL_RWseek(rw, bitmapTableOffset + 0x0C, RW_SEEK_SET) < 0) return -1;
-	Uint16 nameNameCount = SDL_ReadLE16(rw);
-	Uint16 nameIDCount = SDL_ReadLE16(rw);
-
-	if (SDL_RWseek(rw, 0x08 * nameNameCount, RW_SEEK_CUR) < 0) return -1;
-
-	for (Uint16 i = 0; i < nameIDCount; ++i) {
-		Uint32 nameID = SDL_ReadLE32(rw);
-		if (nameID >= idSkip) nameID -= idSkip;
-		if (nameID >= count) continue;
-
-		Uint32 subdirOffset = SDL_ReadLE32(rw);
-		if (!(subdirOffset & (1 << 31))) {
-			SDL_SetError("bitmap name entry does not point to table");
-			return -1;
-		}
-
-		Sint64 nextName = SDL_RWtell(rw);
-		if (nextName < 0) return -1;
-
-		Uint32 langTableOffset =
-			resourceTableOffset + (subdirOffset & ~(1 << 31));
-
-		if (SDL_RWseek(rw, langTableOffset + 0x0C, RW_SEEK_SET) < 0) return -1;
-		Uint16 langNameCount = SDL_ReadLE16(rw);
-		Uint16 langIDCount = SDL_ReadLE16(rw);
-		if (langNameCount != 0 || langIDCount != 1) {
-			SDL_SetError("language table contains more than one entry");
-			return -1;
-		}
-
-		/* Uint32 langID = */ SDL_ReadLE32(rw);
-		Uint32 dataEntryOffset = SDL_ReadLE32(rw);
-		if (dataEntryOffset & (1 << 31)) {
-			SDL_SetError("language entry does not point to data");
-			return -1;
-		}
-		dataEntryOffset += resourceTableOffset;
-
-		if (SDL_RWseek(rw, dataEntryOffset, RW_SEEK_SET) < 0) return -1;
-		Uint32 dataVirtual = SDL_ReadLE32(rw);
-		Uint32 dataLength = SDL_ReadLE32(rw);
-		Uint32 dataOffset =
-			dataVirtual - (resourceTableVirtual - resourceTableOffset);
-
-		surfaces[nameID] = dibSurface(rw, dataOffset, dataLength);
-		if (!surfaces[nameID]) return -1;
-
-		if (SDL_RWseek(rw, nextName, RW_SEEK_SET) < 0) return -1;
-	}
-
-	return 0;
-}
-
-static int
-loadEXE(SDL_Surface **surfaces, size_t count, SDL_RWops *rw, Uint32 idSkip) {
-	if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0) return -1;
-	if (SDL_ReadU8(rw) != 'M' || SDL_ReadU8(rw) != 'Z') {
-		SDL_SetError("invalid MZ signature");
-		return -1;
-	}
-
-	if (SDL_RWseek(rw, 0x3C, RW_SEEK_SET) < 0) return -1;
-	Uint16 offset = SDL_ReadLE16(rw);
-
-	if (SDL_RWseek(rw, offset, RW_SEEK_SET) < 0) return -1;
-	Uint8 sig[2] = { SDL_ReadU8(rw), SDL_ReadU8(rw) };
-
-	if (sig[0] == 'N' && sig[1] == 'E') {
-		return loadNE(surfaces, count, rw, offset, idSkip);
-	} else if (sig[0] == 'P' && sig[1] == 'E') {
-		return loadPE(surfaces, count, rw, offset, idSkip);
-	} else {
-		SDL_SetError("invalid NE/PE signature");
-		return -1;
-	}
-}
-
-static int setColorKey(SDL_Surface **surfaces, size_t count) {
-	size_t i = Cards_Empty;
-	if (i < count) {
-		if (SDL_SetColorKey(surfaces[i], SDL_TRUE, 1) < 0) return -1;
-	}
-	for (i = Cards_X; i <= Cards_O; ++i) {
-		if (i >= count) break;
-		if (SDL_SetColorKey(surfaces[i], SDL_TRUE, 12) < 0) return -1;
-	}
-	return 0;
-}
-
-static int setAlphaCorners(SDL_Surface **surfaces, size_t count) {
-	SDL_Surface *alpha = NULL;
-	for (size_t i = 0; i < count; ++i) {
-		if (!surfaces[i]) continue;
-
-		alpha = SDL_ConvertSurfaceFormat(surfaces[i], SDL_PIXELFORMAT_RGBA32, 0);
-		if (!alpha) return -1;
-
-		if (SDL_SetSurfaceBlendMode(alpha, SDL_BLENDMODE_BLEND) < 0) goto fail;
-
-		SDL_Rect rects[8] = {
-			{ 0, 0, 2, 1 },
-			{ 0, 1, 1, 1 },
-			{ Cards_CardWidth - 2, 0, 2, 1 },
-			{ Cards_CardWidth - 1, 1, 1, 1 },
-			{ 0, Cards_CardHeight - 1, 2, 1 },
-			{ 0, Cards_CardHeight - 2, 1, 1 },
-			{ Cards_CardWidth - 2, Cards_CardHeight - 1, 2, 1 },
-			{ Cards_CardWidth - 1, Cards_CardHeight - 2, 1, 1 },
-		};
-		Uint32 trans = SDL_MapRGBA(alpha->format, 0x00, 0x00, 0x00, 0x00);
-		if (SDL_FillRects(alpha, rects, 8, trans) < 0) goto fail;
-
-		SDL_FreeSurface(surfaces[i]);
-		surfaces[i] = alpha;
-	}
-	return 0;
-
-fail:
-	SDL_FreeSurface(alpha);
-	return -1;
-}
-
-static int setBlackBorders(SDL_Surface **surfaces, size_t count) {
-	for (size_t i = Cards_Diamond + Cards_A; i <= Cards_Heart + Cards_K; ++i) {
-		if (i >= count) break;
-		if (!surfaces[i]) continue;
-		SDL_Rect rects[8] = {
-			{ 2, 0, Cards_CardWidth - 4, 1 },
-			{ 2, Cards_CardHeight - 1, Cards_CardWidth - 4, 1 },
-			{ 0, 2, 1, Cards_CardHeight - 4 },
-			{ Cards_CardWidth - 1, 2, 1, Cards_CardHeight - 4 },
-			{ 1, 1, 1, 1 },
-			{ Cards_CardWidth - 2, 1, 1, 1 },
-			{ 1, Cards_CardHeight - 2, 1, 1 },
-			{ Cards_CardWidth - 2, Cards_CardHeight - 2, 1, 1 },
-		};
-		Uint32 black = SDL_MapRGB(surfaces[i]->format, 0x00, 0x00, 0x00);
-		if (SDL_FillRects(surfaces[i], rects, 8, black) < 0) return -1;
-	}
-	return 0;
-}
-
-static int
-checkRange(SDL_Surface **surfaces, size_t count, size_t a, size_t b) {
-	for (size_t i = a; i <= b; ++i) {
-		if (i >= count) break;
-		if (surfaces[i]) continue;
-		SDL_SetError("missing resource %zu", i);
-		return -1;
-	}
-	return 0;
-}
-
-int
-Cards_LoadCards(
-	SDL_Surface *surfaces[], size_t count,
-	SDL_RWops *rw, enum Cards_Flag flags
-) {
-	memset(surfaces, 0, sizeof(*surfaces) * count);
-	if (loadEXE(surfaces, count, rw, 0) < 0) return -1;
-	if (checkRange(surfaces, count, Cards_A, Cards_Back12) < 0) return -1;
-	if (checkRange(surfaces, count, Cards_X, Cards_O) < 0) return -1;
-	if (flags & Cards_ColorKey) {
-		if (setColorKey(surfaces, count) < 0) return -1;
-	}
-	if (flags & Cards_AlphaCorners) {
-		if (setAlphaCorners(surfaces, count) < 0) return -1;
-	}
-	if (flags & Cards_BlackBorders) {
-		if (setBlackBorders(surfaces, count) < 0) return -1;
-	}
-	return 0;
-}
-
-int
-Cards_LoadFreeCell(
-	SDL_Surface *surfaces[], size_t count,
-	SDL_RWops *rw, enum Cards_Flag flags
-) {
-	memset(surfaces, 0, sizeof(*surfaces) * count);
-	if (loadEXE(surfaces, count, rw, 402) < 0) return -1;
-	if (checkRange(surfaces, count, Cards_KingRight, Cards_KingWin) < 0) {
-		return -1;
-	}
-	if (flags & Cards_ColorKey) {
-		for (size_t i = Cards_KingRight; i <= Cards_KingWin; ++i) {
-			if (i >= count) break;
-			if (SDL_SetColorKey(surfaces[i], SDL_TRUE, 2) < 0) return -1;
-		}
-	}
-	return 0;
-}
-
-static int invertPalette(SDL_Surface *surface) {
-	const SDL_Palette *palette = surface->format->palette;
-	SDL_Palette *invert = SDL_AllocPalette(palette->ncolors);
-	if (!invert) return -1;
-	for (int i = 0; i < invert->ncolors; ++i) {
-		invert->colors[i].r = ~palette->colors[i].r;
-		invert->colors[i].g = ~palette->colors[i].g;
-		invert->colors[i].b = ~palette->colors[i].b;
-		invert->colors[i].a =  palette->colors[i].a;
-	}
-	if (SDL_SetSurfacePalette(surface, invert) < 0) return -1;
-	SDL_FreePalette(invert);
-	return 0;
-}
-
-static int invertPixels(SDL_Surface *surface) {
-	if (SDL_LockSurface(surface) < 0) return -1;
-	Uint8 *pixels = surface->pixels;
-	for (int y = 0; y < surface->h; ++y) {
-		Uint32 *row = (Uint32 *)&pixels[y * surface->pitch];
-		for (int x = 0; x < surface->w; ++x) {
-			Uint32 color = ~row[x] & ~surface->format->Amask;
-			Uint32 alpha = row[x] & surface->format->Amask;
-			row[x] = color | alpha;
-		}
-	}
-	SDL_UnlockSurface(surface);
-	return 0;
-}
-
-int Cards_InvertSurface(SDL_Surface *surface) {
-	if (surface->format->palette) {
-		if (invertPalette(surface) < 0) return -1;
-	} else if (surface->format->BytesPerPixel == 4) {
-		if (invertPixels(surface) < 0) return -1;
-	} else {
-		SDL_SetError("cannot invert surface format");
-		return -1;
-	}
-	return 0;
-}
diff --git a/cards.h b/cards.h
deleted file mode 100644
index 9625cb8..0000000
--- a/cards.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CARDS_H
-#define CARDS_H
-
-#include <SDL_rwops.h>
-#include <SDL_surface.h>
-#include <stddef.h>
-
-enum {
-	Cards_CardWidth = 71,
-	Cards_CardHeight = 96,
-	Cards_KingWidth = 32,
-	Cards_KingHeight = 32,
-};
-
-enum Cards_Card {
-	Cards_Club,
-	Cards_Diamond = 13,
-	Cards_Heart = 26,
-	Cards_Spade = 39,
-
-	// Add rank to suit to obtain card index.
-	Cards_A = 1,
-	Cards_2, Cards_3, Cards_4, Cards_5, Cards_6, Cards_7, Cards_8, Cards_9,
-	Cards_10, Cards_J, Cards_Q, Cards_K,
-
-	Cards_Empty = 53,
-	Cards_Back1, Cards_Back2, Cards_Back3, Cards_Back4,
-	Cards_Back5, Cards_Back6, Cards_Back7, Cards_Back8,
-	Cards_Back9, Cards_Back10, Cards_Back11, Cards_Back12,
-
-	Cards_X = 67,
-	Cards_O,
-
-	Cards_CardCount,
-};
-
-enum Cards_FreeCell {
-	Cards_KingRight = 1,
-	Cards_KingLeft,
-	Cards_KingWin,
-	Cards_FreeCellCount,
-};
-
-enum Cards_Flag {
-	Cards_ColorKey = 1 << 0,
-	Cards_AlphaCorners = 1 << 1,
-	Cards_BlackBorders = 1 << 2,
-};
-
-int
-Cards_LoadCards(
-	SDL_Surface *surfaces[], size_t count,
-	SDL_RWops *rw, enum Cards_Flag flags
-);
-
-int
-Cards_LoadFreeCell(
-	SDL_Surface *surfaces[], size_t count,
-	SDL_RWops *rw, enum Cards_Flag flags
-);
-
-int Cards_InvertSurface(SDL_Surface *surface);
-
-#endif
diff --git a/dump.1 b/dump.1
deleted file mode 100644
index a7fc3db..0000000
--- a/dump.1
+++ /dev/null
@@ -1,48 +0,0 @@
-.Dd March 29, 2019
-.Dt DUMP 1
-.Os
-.
-.Sh NAME
-.Nm dump
-.Nd dump bitmap resources
-.
-.Sh SYNOPSIS
-.Nm
-.Op Fl abfik
-.Op Ar file
-.
-.Sh DESCRIPTION
-.Nm
-dumps bitmap resources from
-.Pa CARDS.DLL ,
-.Pa SOL.EXE
-or
-.Pa FREECELL.EXE
-files.
-Bitmaps are written to the current directory
-starting with
-.Pa 01.bmp .
-.
-.Pp
-The arguments are as follows:
-.Bl -tag -width Ds
-.It Fl a
-Set the
-.Xr cards 3
-.Dv Cards_AlphaCorners
-flag.
-.It Fl b
-Set the
-.Xr cards 3
-.Dv Cards_BlackBorders
-flag.
-.It Fl f
-Dump FreeCell bitmaps.
-.It Fl i
-Invert the colors of the bitmaps
-.It Fl k
-Set the
-.Xr cards 3
-.Dv Cards_ColorKey
-flag.
-.El
diff --git a/dump.c b/dump.c
deleted file mode 100644
index 127d6b1..0000000
--- a/dump.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#define _XOPEN_SOURCE
-
-#include <err.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sysexits.h>
-#include <unistd.h>
-
-#include <SDL.h>
-
-#include "cards.h"
-
-int main(int argc, char *argv[]) {
-	bool freecell = false;
-	enum Cards_Flag flags = 0;
-	bool invert = false;
-
-	int opt;
-	while (0 < (opt = getopt(argc, argv, "abfik"))) {
-		switch (opt) {
-			break; case 'a': flags |= Cards_AlphaCorners;
-			break; case 'b': flags |= Cards_BlackBorders;
-			break; case 'f': freecell = true;
-			break; case 'i': invert = true;
-			break; case 'k': flags |= Cards_ColorKey;
-			break; default:  return EX_USAGE;
-		}
-	}
-
-	struct SDL_RWops *rw;
-	if (optind < argc) {
-		rw = SDL_RWFromFile(argv[optind], "rb");
-	} else {
-		rw = SDL_RWFromFP(stdin, SDL_FALSE);
-	}
-	if (!rw) errx(EX_NOINPUT, "SDL_RWFromFile: %s", SDL_GetError());
-
-	SDL_Surface *surfaces[Cards_CardCount];
-	if (freecell) {
-		int error = Cards_LoadFreeCell(
-			surfaces, Cards_CardCount, rw, flags
-		);
-		if (error) errx(EX_DATAERR, "Cards_LoadFreeCell: %s", SDL_GetError());
-	} else {
-		int error = Cards_LoadCards(surfaces, Cards_CardCount, rw, flags);
-		if (error) errx(EX_DATAERR, "Cards_LoadCards: %s", SDL_GetError());
-	}
-	SDL_RWclose(rw);
-
-	for (size_t i = 0; i < Cards_CardCount; ++i) {
-		if (!surfaces[i]) continue;
-
-		if (invert) {
-			int error = Cards_InvertSurface(surfaces[i]);
-			if (error) {
-				errx(EX_DATAERR, "Cards_InvertSurface: %s", SDL_GetError());
-			}
-		}
-
-		char name[sizeof("00.bmp")];
-		snprintf(name, sizeof(name), "%02zu.bmp", i);
-		int error = SDL_SaveBMP(surfaces[i], name);
-		if (error) errx(EX_CANTCREAT, "SDL_SaveBMP: %s", SDL_GetError());
-	}
-}
diff --git a/exefmt.txt b/exefmt.txt
deleted file mode 100644
index 51fa9a7..0000000
--- a/exefmt.txt
+++ /dev/null
@@ -1,593 +0,0 @@
-INF: Executable-File Header Format                            [P_WinSDK]
-
-3.00
-WINDOWS
-PSSONLY | Windows 3 Developers Notes softlib ENDUSER
-
-Summary:
-
-Note: This article is part of a set of seven articles, collectively
-called the "Windows 3.00 Developer's Notes." More information about
-the contents of the other articles, and procedures for ordering a
-hard-copy set, can be found in the knowledge base article titled "INF:
-The Windows 3.00 Developer's Notes" (Q65260).
-
-This article can be found in the Software/Data Library by searching on
-the word EXEFMT or S12688. EXEFMT was archived using the PKware
-file-compression utility.
-
-More Information:
-
-Microsoft defined the segmented executable file format for Windows
-applications and dynamic-link libraries (DLLs). This file format is
-also referred to as the New Executable Format. This new format is an
-extension of the existing MS-DOS .EXE format (old-style format). The
-purpose of the segmented executable format is to provide the
-information needed to support the dynamic linking and segmentation
-capabilities of the Windows environment.
-
-An executable file contains Microsoft Windows code and data, or
-Windows code, data, and resources. Specific fields have been added to
-the old-style .EXE format header to indicate the existence of the
-segmented file format. The old-style header may contain a valid
-executable program, called a stub program, that will be executed if
-the program is run on MS-DOS (without Windows). This stub program
-usually prints a message indicating that Microsoft Windows is required
-to run the program. The segmented executable format extensions also
-begin with a header that describes the contents and location of the
-executable image in the file. The loader uses this header information
-when it loads the executable segments in memory.
-
-
-======================================================================
-                     OLD-STYLE HEADER EXTENSIONS
-======================================================================
-
-The old-style header contains information the loader expects for a DOS
-executable file. It describes a stub program (WINSTUB) the loader can
-place in memory when necessary, it points to the new-style header, and
-it contains the stub programs relocation table.
-
-The following illustrates the distinct parts of the old-style
-executable format:
-
-        +-------------------------+
-    00h |  Old-style header info  |
-        +-------------------------+
-    20h |        Reserved         |
-        +-------------------------+
-    3Ch |   Offset to segmented   |
-        |       .EXE header       |
-        +-------------------------+
-    40h |  Relocation table and   |
-        |    DOS stub program     |
-        +-------------------------+
-        |  Segmented .EXE Header  |
-        |           .             |
-        |           .             |
-        |           .             |
-
-The word at offset 18h in the old-style .EXE header contains the
-relative byte offset to the stub program's relocation table. If this
-offset is 40h, then the double word at offset 3Ch is assumed to be the
-relative byte offset from the beginning of the file to the beginning
-of the segmented executable header. A new-format .EXE file is
-identified if the segmented executable header contains a valid
-signature. If the signature is not valid, the file is assumed to be an
-old-style format .EXE file. The remainder of the old-style format
-header will describe a DOS program, the stub. The stub may be any
-valid program but will typically be a program that displays an error
-message.
-
-======================================================================
-                         SEGMENTED EXE FORMAT
-======================================================================
-
-Because Windows executable files are often larger than one segment
-(64K), additional information (that does not appear in the old-style
-header) is required so that the loader can load each segment properly.
-The segmented EXE format was developed to provide the loader with this
-information.
-
-The segmented .EXE file has the following format:
-
-        +-----------------+
-    00h |  Old-style EXE  |
-        |      Header     |
-        +-----------------+
-    20h |    Reserved     |
-        +-----------------+
-    3Ch |    Offset to    | ---+
-        | Segmented Header|    |
-        +-----------------+    |
-    40h | Relocation Table|    |
-        |  & Stub Program |    |
-        +-----------------+    |
-        |                 |    |
-        +-----------------+    |
-    xxh |  Segmented EXE  | <--+
-        |      Header     |
-        +-----------------+
-        |  Segment Table  |
-        +-----------------+
-        | Resource Table  |
-        +-----------------+
-        |  Resident Name  |
-        |      Table      |
-        +-----------------+
-        | Module Reference|
-        |      Table      |
-        +-----------------+
-        | Imported Names  |
-        |      Table      |
-        +-----------------+
-        |   Entry Table   |
-        +-----------------+
-        |  Non-Resident   |
-        |   Name Table    |
-        +-----------------+
-        |   Seg #1 Data   |
-        |   Seg #1 Info   |
-        +-----------------+
-                .
-                .
-                .
-        +-----------------+
-        |   Seg #n Data   |
-        |   Seg #n Info   |
-        +-----------------+
-
-
-The following sections describe each of the components that make up
-the segmented EXE format. Each section contains a description of the
-component and the fields in the structures that make up that
-component.
-
-Note: All unused fields and flag bits are reserved for future use and
-must contain 0 (zero) values.
-
-======================================================================
-                         SEGMENTED EXE HEADER
-======================================================================
-
-The segmented EXE header contains general information about the EXE
-file and contains information on the location and size of the other
-sections. The Windows loader copies this section, along with other
-data, into the module table in the system data. The module table is
-internal data used by the loader to manage the loaded executable
-modules in the system and to support dynamic linking.
-
-The following describes the format of the segmented executable header.
-For each field, the offset is given relative to the beginning of the
-segmented header, the size of the field is defined, and a description
-is given.
-
-    Offset Size Description
-    ------ ---- -----------
-
-    00h     DW  Signature word.
-                "N" is low-order byte.
-                "E" is high-order byte.
-
-    02h     DB  Version number of the linker.
-
-    03h     DB  Revision number of the linker.
-
-    04h     DW  Entry Table file offset, relative to the beginning of
-                the segmented EXE header.
-    06h     DW  Number of bytes in the entry table.
-
-    08h     DD  32-bit CRC of entire contents of file.
-                These words are taken as 00 during the calculation.
-
-    0Ch     DW  Flag word.
-                0000h = NOAUTODATA
-                0001h = SINGLEDATA (Shared automatic data segment)
-                0002h = MULTIPLEDATA (Instanced automatic data
-                        segment)
-                2000h = Errors detected at link time, module will not
-                        load.
-                8000h = Library module.
-                        The SS:SP information is invalid, CS:IP points
-                        to an initialization procedure that is called
-                        with AX equal to the module handle. This
-                        initialization procedure must perform a far
-                        return to the caller, with AX not equal to
-                        zero to indicate success, or AX equal to zero
-                        to indicate failure to initialize. DS is set
-                        to the library's data segment if the
-                        SINGLEDATA flag is set. Otherwise, DS is set
-                        to the caller's data segment.
-
-                        A program or DLL can only contain dynamic
-                        links to executable files that have this
-                        library module flag set. One program cannot
-                        dynamic-link to another program.
-
-    0Eh     DW  Segment number of automatic data segment.
-                This value is set to zero if SINGLEDATA and
-                MULTIPLEDATA flag bits are clear, NOAUTODATA is
-                indicated in the flags word.
-
-                A Segment number is an index into the module's segment
-                table. The first entry in the segment table is segment
-                number 1.
-
-    10h     DW  Initial size, in bytes, of dynamic heap added to the
-                data segment. This value is zero if no initial local
-                heap is allocated.
-
-    12h     DW  Initial size, in bytes, of stack added to the data
-                segment. This value is zero to indicate no initial
-                stack allocation, or when SS is not equal to DS.
-
-    14h     DD  Segment number:offset of CS:IP.
-
-    18h     DD  Segment number:offset of SS:SP.
-                If SS equals the automatic data segment and SP equals
-                zero, the stack pointer is set to the top of the
-                automatic data segment just below the additional heap
-                area.
-
-                    +--------------------------+
-                    | additional dynamic heap  |
-                    +--------------------------+ <- SP
-                    |    additional stack      |
-                    +--------------------------+
-                    | loaded auto data segment |
-                    +--------------------------+ <- DS, SS
-
-    1Ch     DW  Number of entries in the Segment Table.
-
-    1Eh     DW  Number of entries in the Module Reference Table.
-    20h     DW  Number of bytes in the Non-Resident Name Table.
-
-    22h     DW  Segment Table file offset, relative to the beginning
-                of the segmented EXE header.
-
-    24h     DW  Resource Table file offset, relative to the beginning
-                of the segmented EXE header.
-
-    26h     DW  Resident Name Table file offset, relative to the
-                beginning of the segmented EXE header.
-
-    28h     DW  Module Reference Table file offset, relative to the
-                beginning of the segmented EXE header.
-
-    2Ah     DW  Imported Names Table file offset, relative to the
-                beginning of the segmented EXE header.
-
-    2Ch     DD  Non-Resident Name Table offset, relative to the
-                beginning of the file.
-
-    30h     DW  Number of movable entries in the Entry Table.
-
-    32h     DW  Logical sector alignment shift count, log(base 2) of
-                the segment sector size (default 9).
-
-    34h     DW  Number of resource entries.
-
-    36h     DB  Executable type, used by loader.
-                  02h = WINDOWS
-
-    37h-3Fh DB  Reserved, currently 0's.
-
-
-======================================================================
-                            SEGMENT TABLE
-======================================================================
-
-The segment table contains an entry for each segment in the executable
-file. The number of segment table entries are defined in the segmented
-EXE header. The first entry in the segment table is segment number 1.
-The following is the structure of a segment table entry.
-
-   Size Description
-   ---- -----------
-
-   DW   Logical-sector offset (n byte) to the contents of the segment
-        data, relative to the beginning of the file. Zero means no
-        file data.
-
-   DW   Length of the segment in the file, in bytes. Zero means 64K.
-
-   DW   Flag word.
-        0007h = TYPE_MASK  Segment-type field.
-        0000h = CODE       Code-segment type.
-        0001h = DATA       Data-segment type.
-        0010h = MOVEABLE   Segment is not fixed.
-        0040h = PRELOAD    Segment will be preloaded; read-only if
-                           this is a data segment.
-        0100h = RELOCINFO  Set if segment has relocation records.
-        F000h = DISCARD    Discard priority.
-
-   DW   Minimum allocation size of the segment, in bytes. Total size
-        of the segment. Zero means 64K.
-
-
-======================================================================
-                            RESOURCE TABLE
-======================================================================
-
-The resource table follows the segment table and contains entries for
-each resource in the executable file. The resource table consists of
-an alignment shift count, followed by a table of resource records. The
-resource records define the type ID for a set of resources. Each
-resource record contains a table of resource entries of the defined
-type. The resource entry defines the resource ID or name ID for the
-resource. It also defines the location and size of the resource. The
-following describes the contents of each of these structures:
-
-   Size Description
-   ---- -----------
-
-   DW   Alignment shift count for resource data.
-
-   A table of resource type information blocks follows. The following
-   is the format of each type information block:
-
-        DW  Type ID. This is an integer type if the high-order bit is
-            set (8000h); otherwise, it is an offset to the type string,
-            the offset is relative to the beginning of the resource
-            table. A zero type ID marks the end of the resource type
-            information blocks.
-
-        DW  Number of resources for this type.
-
-        DD  Reserved.
-
-        A table of resources for this type follows. The following is
-        the format of each resource (8 bytes each):
-
-            DW  File offset to the contents of the resource data,
-                relative to beginning of file. The offset is in terms
-                of the alignment shift count value specified at
-                beginning of the resource table.
-
-            DW  Length of the resource in the file (in bytes).
-
-            DW  Flag word.
-                0010h = MOVEABLE  Resource is not fixed.
-                0020h = PURE      Resource can be shared.
-                0040h = PRELOAD   Resource is preloaded.
-
-            DW  Resource ID. This is an integer type if the high-order
-                bit is set (8000h), otherwise it is the offset to the
-                resource string, the offset is relative to the
-                beginning of the resource table.
-
-            DD  Reserved.
-
-   Resource type and name strings are stored at the end of the
-   resource table. Note that these strings are NOT null terminated and
-   are case sensitive.
-
-   DB   Length of the type or name string that follows. A zero value
-        indicates the end of the resource type and name string, also
-        the end of the resource table.
-
-   DB   ASCII text of the type or name string.
-
-
-======================================================================
-                         RESIDENT-NAME TABLE
-======================================================================
-
-The resident-name table follows the resource table, and contains this
-module's name string and resident exported procedure name strings. The
-first string in this table is this module's name. These name strings
-are case-sensitive and are not null-terminated. The following
-describes the format of the name strings:
-
-   Size Description
-   ---- -----------
-
-   DB   Length of the name string that follows. A zero value indicates
-        the end of the name table.
-
-   DB   ASCII text of the name string.
-
-   DW   Ordinal number (index into entry table). This value is ignored
-        for the module name.
-
-
-======================================================================
-                        MODULE-REFERENCE TABLE
-======================================================================
-
-The module-reference table follows the resident-name table. Each entry
-contains an offset for the module-name string within the imported-
-names table; each entry is 2 bytes long.
-
-   Size Description
-   ---- -----------
-
-   DW   Offset within Imported Names Table to referenced module name
-        string.
-
-
-======================================================================
-                         IMPORTED-NAME TABLE
-======================================================================
-
-The imported-name table follows the module-reference table. This table
-contains the names of modules and procedures that are imported by the
-executable file. Each entry is composed of a 1-byte field that
-contains the length of the string, followed by any number of
-characters. The strings are not null-terminated and are case
-sensitive.
-
-   Size Description
-   ---- -----------
-
-   DB   Length of the name string that follows.
-
-   DB   ASCII text of the name string.
-
-
-======================================================================
-                             ENTRY TABLE
-======================================================================
-
-The entry table follows the imported-name table. This table contains
-bundles of entry-point definitions. Bundling is done to save space in
-the entry table. The entry table is accessed by an ordinal value.
-Ordinal number one is defined to index the first entry in the entry
-table. To find an entry point, the bundles are scanned searching for a
-specific entry point using an ordinal number. The ordinal number is
-adjusted as each bundle is checked. When the bundle that contains the
-entry point is found, the ordinal number is multiplied by the size of
-the bundle's entries to index the proper entry.
-
-The linker forms bundles in the most dense manner it can, under the
-restriction that it cannot reorder entry points to improve bundling.
-The reason for this restriction is that other .EXE files may refer to
-entry points within this bundle by their ordinal number. The following
-describes the format of the entry table bundles.
-
-   Size Description
-   ---- -----------
-
-   DB   Number of entries in this bundle. All records in one bundle
-        are either moveable or refer to the same fixed segment. A zero
-        value in this field indicates the end of the entry table.
-
-   DB   Segment indicator for this bundle. This defines the type of
-        entry table entry data within the bundle. There are three
-        types of entries that are defined.
-
-        000h = Unused entries. There is no entry data in an unused
-               bundle. The next bundle follows this field. This is
-               used by the linker to skip ordinal numbers.
-
-        001h-0FEh = Segment number for fixed segment entries. A fixed
-               segment entry is 3 bytes long and has the following
-               format.
-
-            DB  Flag word.
-                01h = Set if the entry is exported.
-                02h = Set if the entry uses a global (shared) data
-                      segments.
-                      The first assembly-language instruction in the
-                      entry point prologue must be "MOV AX,data
-                      segment number". This may be set only for
-                      SINGLEDATA library modules.
-
-            DW  Offset within segment to entry point.
-
-        0FFH = Moveable segment entries. The entry data contains the
-               segment number for the entry points. A moveable segment
-               entry is 6 bytes long and has the following format.
-
-            DB  Flag word.
-                01h = Set if the entry is exported.
-                02h = Set if the entry uses a global (shared) data
-                      segments.
-
-            INT 3FH.
-
-            DB  Segment number.
-
-            DW  Offset within segment to entry point.
-
-
-======================================================================
-                        NONRESIDENT-NAME TABLE
-======================================================================
-
-The nonresident-name table follows the entry table, and contains a
-module description and nonresident exported procedure name strings.
-The first string in this table is a module description. These name
-strings are case-sensitive and are not null-terminated. The name
-strings follow the same format as those defined in the resident name
-table.
-
-
-======================================================================
-                           PER SEGMENT DATA
-======================================================================
-
-The location and size of the per-segment data is defined in the
-segment table entry for the segment. If the segment has relocation
-fixups, as defined in the segment table entry flags, they directly
-follow the segment data in the file. The relocation fixup information
-is defined as follows:
-
-
-   Size Description
-   ---- -----------
-
-   DW   Number of relocation records that follow.
-
-   A table of relocation records follows. The following is the format
-   of each relocation record.
-
-        DB  Source type.
-            0Fh = SOURCE_MASK
-            00h = LOBYTE
-            02h = SEGMENT
-            03h = FAR_ADDR (32-bit pointer)
-            05h = OFFSET (16-bit offset)
-
-        DB  Flags byte.
-            03h = TARGET_MASK
-            00h = INTERNALREF
-            01h = IMPORTORDINAL
-            02h = IMPORTNAME
-            03h = OSFIXUP
-            04h = ADDITIVE
-
-        DW  Offset within this segment of the source chain.
-            If the ADDITIVE flag is set, then target value is added to
-            the source contents, instead of replacing the source and
-            following the chain. The source chain is an 0FFFFh
-            terminated linked list within this segment of all
-            references to the target.
-
-        The target value has four types that are defined in the flag
-        byte field. The following are the formats for each target
-        type:
-
-        INTERNALREF
-
-            DB  Segment number for a fixed segment, or 0FFh for a
-                movable segment.
-
-            DB  0
-
-            DW  Offset into segment if fixed segment, or ordinal
-                number index into Entry Table if movable segment.
-
-        IMPORTNAME
-
-            DW  Index into module reference table for the imported
-                module.
-
-            DW  Offset within Imported Names Table to procedure name
-                string.
-
-        IMPORTORDINAL
-
-            DW  Index into module reference table for the imported
-                module.
-            DW  Procedure ordinal number.
-
-        OSFIXUP
-
-            DW  Operating system fixup type.
-                Floating-point fixups.
-                0001h = FIARQQ, FJARQQ
-                0002h = FISRQQ, FJSRQQ
-                0003h = FICRQQ, FJCRQQ
-                0004h = FIERQQ
-                0005h = FIDRQQ
-                0006h = FIWRQQ
-
-            DW  0
-
-======================================================================
-
-Microsoft is a registered trademark and Windows is a trademark of
-Microsoft Corporation.
-
-Additional reference words: 3.0