summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile9
-rw-r--r--cards.c214
-rw-r--r--cards.h52
-rw-r--r--dump.c59
5 files changed, 188 insertions, 149 deletions
diff --git a/.gitignore b/.gitignore
index eea74f3..3c9fa20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
+*.bmp
 *.o
+CARDS.DLL
+SOL.EXE
 dump
diff --git a/Makefile b/Makefile
index b58b5e5..2ba46a6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,17 @@
-CFLAGS += -Wall -Wextra
+CFLAGS += -std=c99 -Wall -Wextra
+
+SDL_PREFIX = /usr/local
+CFLAGS += -I$(SDL_PREFIX)/include/SDL2
+LDFLAGS += -L$(SDL_PREFIX)/lib
+LDLIBS = -lSDL2
 
 -include config.mk
 
 BINS = dump
 OBJS = cards.o dump.o
 
+all: $(BINS)
+
 dump: cards.o dump.o
 	$(CC) $(LDFLAGS) cards.o dump.o $(LDLIBS) -o dump
 
diff --git a/cards.c b/cards.c
index 52445a1..6369d40 100644
--- a/cards.c
+++ b/cards.c
@@ -14,124 +14,168 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "cards.h"
 
-enum {
-	MZ_NEOff = 0x3C,
+static struct SDL_Surface *
+dibSurface(struct SDL_RWops *rw, Uint32 offset, Uint32 length) {
+	Uint32 bitmapLength = 0x0E + length;
 
-	NE_ResTableOff = 0x24,
-
-	ResTable_AlignShift = 0x00,
-	ResTable_ResBlock = 0x02,
-
-	ResBlock_TypeID = 0x00,
-	ResBlock_ResCount = 0x02,
-	ResBlock_Resource = 0x08,
-
-	TypeID_Bitmap = 0x8002,
+	void *buffer = malloc(bitmapLength);
+	if (!buffer) {
+		SDL_SetError("malloc error: %s", strerror(errno));
+		return NULL;
+	}
 
-	Resource_Off = 0x00,
-	Resource_Len = 0x02,
-	Resource_ID = 0x06,
-	Resource_Next = 0x0C,
+	struct SDL_RWops *bitmap = SDL_RWFromMem(buffer, bitmapLength);
+	if (!bitmap) {
+		free(buffer);
+		return NULL;
+	}
 
-	IDMask = 0x7FFF,
+	if (SDL_RWseek(rw, offset, RW_SEEK_SET) < 0) goto fail;
+	Uint32 dibHeaderLength = SDL_ReadLE32(rw);
+	Uint32 bitmapDataOffset = 0x0E + dibHeaderLength;
 
-	BMPHeader_FileLen = 0x02,
-	BMPHeader_Reserved = 0x06,
-	BMPHeader_DataOff = 0x0A,
-	BMPHeader_DIBHeader = 0x0E,
+	if (dibHeaderLength == 0x0C) {
+		if (SDL_RWseek(rw, 0x06, RW_SEEK_CUR) < 0) goto fail;
+		Uint16 bitsPerPixel = SDL_ReadLE16(rw);
+		bitmapDataOffset += 3 * (1 << bitsPerPixel);
 
-	DIBHeader_Len = 0x00,
-	DIBHeaderCore_Bits = 0x0A,
+	} 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);
 
-	DIBHeaderCoreLen = 0x0C,
-};
+		if (!paletteLength) paletteLength = 1 << bitsPerPixel;
+		bitmapDataOffset += 4 * paletteLength;
 
-static uint16_t read16(const uint8_t *ptr, size_t off) {
-	return (uint16_t)ptr[off] | (uint16_t)ptr[off + 1] << 8;
-}
-static uint32_t read32(const uint8_t *ptr, size_t off) {
-	return (uint32_t)ptr[off]
-		| (uint32_t)ptr[off + 1] << 8
-		| (uint32_t)ptr[off + 2] << 16
-		| (uint32_t)ptr[off + 3] << 24;
-}
+	} else {
+		SDL_SetError("unrecognized DIB header length %u", dibHeaderLength);
+		goto fail;
+	}
 
-static void write32(uint8_t *ptr, size_t off, uint32_t val) {
-	ptr[off + 0] = val & 0xFF;
-	ptr[off + 1] = val >> 8 & 0xFF;
-	ptr[off + 2] = val >> 16 & 0xFF;
-	ptr[off + 3] = val >> 24;
+	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;
 }
 
-int cardsLoad(const uint8_t *ptr, size_t len) {
-	if (len < MZ_NEOff + 2) return -1;
-	if (ptr[0] != 'M' || ptr[1] != 'Z') return -1;
+struct Cards *Cards_Load(struct SDL_RWops *rw) {
+	struct Cards *cards = calloc(1, sizeof(*cards));
+	if (!cards) {
+		SDL_SetError("calloc error: %s", strerror(errno));
+		return NULL;
+	}
 
-	uint16_t neOff = read16(ptr, MZ_NEOff);
+	if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0) goto fail;
+	if (SDL_ReadU8(rw) != 'M' || SDL_ReadU8(rw) != 'Z') {
+		SDL_SetError("invalid MZ signature");
+		goto fail;
+	}
 
-	if (len < neOff + NE_ResTableOff + 2) return -1;
-	if (ptr[neOff + 0] != 'N' || ptr[neOff + 1] != 'E') return -1;
+	if (SDL_RWseek(rw, 0x3C, RW_SEEK_SET) < 0) goto fail;
+	Uint16 neOffset = SDL_ReadLE16(rw);
 
-	uint16_t resTableOff = neOff + read16(ptr, neOff + NE_ResTableOff);
+	if (SDL_RWseek(rw, neOffset, RW_SEEK_SET) < 0) goto fail;
+	if (SDL_ReadU8(rw) != 'N' || SDL_ReadU8(rw) != 'E') {
+		SDL_SetError("invalid NE signature");
+		goto fail;
+	}
 
-	if (len < resTableOff + ResTable_ResBlock) return -1;
+	if (SDL_RWseek(rw, neOffset + 0x24, RW_SEEK_SET) < 0) goto fail;
+	Uint16 resourceTableOffset = neOffset + SDL_ReadLE16(rw);
 
-	uint16_t alignShift = read16(ptr, resTableOff + ResTable_AlignShift);
+	if (SDL_RWseek(rw, resourceTableOffset, RW_SEEK_SET) < 0) goto fail;
+	Uint16 alignmentShift = SDL_ReadLE16(rw);
 
-	uint16_t resBlockOff = resTableOff + ResTable_ResBlock;
-	uint16_t resCount;
+	Uint16 resourceCount;
 	for (;;) {
-		if (len < resBlockOff + ResBlock_Resource) return -1;
-
-		uint16_t typeID = read16(ptr, resBlockOff + ResBlock_TypeID);
-		resCount = read16(ptr, resBlockOff + ResBlock_ResCount);
+		Uint16 typeID = SDL_ReadLE16(rw);
+		resourceCount = SDL_ReadLE16(rw);
+		SDL_ReadLE32(rw); // reserved
 
-		if (!typeID) return -1;
-		if (typeID == TypeID_Bitmap) break;
+		if (!typeID) {
+			SDL_SetError("no bitmap resources");
+			goto fail;
+		}
+		if (typeID == 0x8002) break;
 
-		resBlockOff += ResBlock_Resource + resCount * Resource_Next;
+		if (SDL_RWseek(rw, 0x0C * resourceCount, RW_SEEK_CUR) < 0) goto fail;
 	}
 
-	uint16_t resOff = resBlockOff + ResBlock_Resource;
-	for (uint16_t i = 0; i < resCount; ++i, resOff += Resource_Next) {
-		if (len < resOff + Resource_Next) return -1;
+	for (Uint16 i = 0; i < resourceCount; ++i) {
+		Uint16 offset = SDL_ReadLE16(rw);
+		Uint16 length = SDL_ReadLE16(rw);
+		SDL_ReadLE16(rw); // flags
+		Uint16 id = SDL_ReadLE16(rw);
+		SDL_ReadLE32(rw); // reserved
 
-		uint16_t id = read16(ptr, resOff + Resource_ID);
-		if ((id & IDMask) >= CardsLen) continue;
+		id &= 0x7FFF;
+		if (id >= Cards_CardLen) continue;
 
-		size_t dataOff = read16(ptr, resOff + Resource_Off);
-		size_t dataLen = read16(ptr, resOff + Resource_Len);
-		dataOff <<= alignShift;
-		dataLen <<= alignShift;
+		Sint64 next = SDL_RWtell(rw);
+		if (next < 0) goto fail;
 
-		if (len < dataOff + dataLen) return -1;
-		if (dataLen < DIBHeaderCoreLen) return -1;
+		cards->surfaces[id] = dibSurface(
+			rw,
+			(Uint32)offset << alignmentShift,
+			(Uint32)length << alignmentShift
+		);
+		if (!cards->surfaces[id]) goto fail;
+
+		if (SDL_RWseek(rw, next, RW_SEEK_SET) < 0) goto fail;
+	}
 
-		uint32_t dibHeaderLen = read32(ptr, dataOff + DIBHeader_Len);
-		uint32_t bmpFileLen = BMPHeader_DIBHeader + dataLen;
-		uint32_t bmpDataOff = BMPHeader_DIBHeader + dibHeaderLen;
-		if (dibHeaderLen == DIBHeaderCoreLen) {
-			bmpDataOff += 3 * (1 << read16(ptr, dataOff + DIBHeaderCore_Bits));
+	int suits[4] = { Cards_Club, Cards_Diamond, Cards_Heart, Cards_Spade };
+	for (int suit = 0; suit < 4; ++suit) {
+		for (int rank = Cards_A; rank <= Cards_K; ++rank) {
+			if (cards->surfaces[suits[suit] + rank]) continue;
+			SDL_SetError("missing resource %d", suits[suit] + rank);
+			goto fail;
 		}
+	}
+	for (int i = Cards_Empty; i <= Cards_Back12; ++i) {
+		if (cards->surfaces[i]) continue;
+		SDL_SetError("missing resource %d", i);
+		goto fail;
+	}
+	for (int i = Cards_X; i <= Cards_O; ++i) {
+		if (cards->surfaces[i]) continue;
+		SDL_SetError("missing resource %d", i);
+		goto fail;
+	}
 
-		uint8_t *bitmap = malloc(bmpFileLen);
-		if (!bitmap) return -1;
+	return cards;
 
-		bitmap[0] = 'B';
-		bitmap[1] = 'M';
-		write32(bitmap, BMPHeader_FileLen, bmpFileLen);
-		write32(bitmap, BMPHeader_Reserved, 0);
-		write32(bitmap, BMPHeader_DataOff, bmpDataOff);
-		memcpy(&bitmap[BMPHeader_DIBHeader], &ptr[dataOff], dataLen);
+fail:
+	Cards_Free(cards);
+	return NULL;
+}
 
-		cardsData[id & IDMask].ptr = bitmap;
-		cardsData[id & IDMask].len = bmpFileLen;
+void Cards_Free(struct Cards *cards) {
+	for (int i = 0; i < Cards_CardLen; ++i) {
+		if (!cards->surfaces[i]) continue;
+		SDL_FreeSurface(cards->surfaces[i]);
 	}
-
-	return 0;
+	free(cards);
 }
diff --git a/cards.h b/cards.h
index 65e3c2b..23a70fb 100644
--- a/cards.h
+++ b/cards.h
@@ -17,33 +17,35 @@
 #ifndef CARDS_H
 #define CARDS_H
 
-#include <stddef.h>
-#include <stdint.h>
-
-enum Cards {
-	CardsClub    = 0x00,
-	CardsDiamond = 0x0D,
-	CardsHeart   = 0x1A,
-	CardsSpade   = 0x27,
-
-	CardsA = 1,
-	Cards2, Cards3, Cards4, Cards5, Cards6, Cards7, Cards8, Cards9, Cards10,
-	CardsJ, CardsQ, CardsK,
-
-	CardsEmpty = 0x35,
-	CardsBack1, CardsBack2, CardsBack3, CardsBack4, CardsBack5, CardsBack6,
-	CardsBack7, CardsBack8, CardsBack9, CardsBack10, CardsBack11, CardsBack12,
-
-	CardsX = 0x43,
-	CardsO,
-	CardsLen,
+#include <SDL_rwops.h>
+#include <SDL_surface.h>
+
+enum Cards_Card {
+	Cards_Club,
+	Cards_Diamond = 13,
+	Cards_Heart = 26,
+	Cards_Spade = 39,
+
+	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_CardLen,
 };
 
-struct CardsData {
-	uint8_t *ptr;
-	size_t len;
-} cardsData[CardsLen];
+struct Cards {
+	struct SDL_Surface *surfaces[Cards_CardLen];
+};
 
-int cardsLoad(const uint8_t *ptr, size_t len);
+struct Cards *Cards_Load(struct SDL_RWops *rw);
+void Cards_Free(struct Cards *cards);
 
 #endif
diff --git a/dump.c b/dump.c
index 0eefc3c..1d3b6dc 100644
--- a/dump.c
+++ b/dump.c
@@ -14,54 +14,37 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <err.h>
-#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sysexits.h>
+
+#include <SDL.h>
 
 #include "cards.h"
 
+static int fail(const char *prefix) {
+	fprintf(stderr, "%s: %s\n", prefix, SDL_GetError());
+	return EXIT_FAILURE;
+}
+
 int main(int argc, char *argv[]) {
-	FILE *file = stdin;
+	struct SDL_RWops *rw;
 	if (argc > 1) {
-		file = fopen(argv[1], "r");
-		if (!file) err(EX_NOINPUT, "%s", argv[1]);
-	}
-
-	size_t cap = 4096;
-	void *ptr = malloc(cap);
-	if (!ptr) err(EX_OSERR, "malloc");
-
-	size_t len = 0, read;
-	while (0 < (read = fread(&ptr[len], 1, cap - len, file))) {
-		len += read;
-		if (len < cap) continue;
-		cap *= 2;
-		ptr = realloc(ptr, cap);
-		if (!ptr) err(EX_OSERR, "realloc");
+		rw = SDL_RWFromFile(argv[1], "rb");
+	} else {
+		rw = SDL_RWFromFP(stdin, SDL_FALSE);
 	}
-	if (ferror(file)) err(EX_IOERR, "fread");
-	fclose(file);
+	if (!rw) return fail("SDL_RWFromFile");
 
-	errno = 0;
-	int error = cardsLoad(ptr, len);
-	if (error && errno) err(EX_OSERR, "cardsLoad");
-	if (error) errx(EX_DATAERR, "cannot load cards");
-
-	for (size_t i = 0; i < CardsLen; ++i) {
-		if (!cardsData[i].ptr) continue;
+	struct Cards *cards = Cards_Load(rw);
+	if (!cards) return fail("Cards_Load");
+	SDL_RWclose(rw);
 
+	for (int i = 0; i < Cards_CardLen; ++i) {
+		if (!cards->surfaces[i]) continue;
 		char name[sizeof("00.bmp")];
-		snprintf(name, sizeof(name), "%02zd.bmp", i);
-
-		FILE *file = fopen(name, "w");
-		if (!file) err(EX_CANTCREAT, "%s", name);
-
-		fwrite(cardsData[i].ptr, cardsData[i].len, 1, file);
-		if (ferror(file)) err(EX_IOERR, "fwrite");
-
-		error = fclose(file);
-		if (error) err(EX_IOERR, "fclose");
+		snprintf(name, sizeof(name), "%02d.bmp", i);
+		SDL_SaveBMP(cards->surfaces[i], name);
 	}
+
+	Cards_Free(cards);
 }