about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2019-03-28 16:13:35 -0400
committerJune McEnroe <june@causal.agency>2019-03-28 16:13:35 -0400
commitf3236a4fbfbc2129729499b24f4140ade308d9f4 (patch)
treeee6a49ee6b718cb0f3ba09cedb25baa96bf9e070
parentAdd keys to reveal ranks (diff)
downloadcards-f3236a4fbfbc2129729499b24f4140ade308d9f4.tar.gz
cards-f3236a4fbfbc2129729499b24f4140ade308d9f4.zip
Refactor EXE/DLL loading to be more general
In order to load the 3 bitmaps from FREECELL.EXE.
-rw-r--r--cards.c70
1 files changed, 38 insertions, 32 deletions
diff --git a/cards.c b/cards.c
index 29aa7a4..b9153a5 100644
--- a/cards.c
+++ b/cards.c
@@ -146,7 +146,8 @@ static int setBlackBorders(struct Cards *cards) {
 }
 
 // exefmt.txt
-static int loadNE(struct Cards *cards, SDL_RWops *rw, Uint16 neOffset) {
+static int
+loadNE(SDL_Surface **surfaces, size_t count, SDL_RWops *rw, Uint16 neOffset) {
 	if (SDL_RWseek(rw, neOffset + 0x24, RW_SEEK_SET) < 0) return -1;
 	Uint16 resourceTableOffset = neOffset + SDL_ReadLE16(rw);
 
@@ -169,33 +170,34 @@ static int loadNE(struct Cards *cards, SDL_RWops *rw, Uint16 neOffset) {
 	}
 
 	for (Uint16 i = 0; i < resourceCount; ++i) {
-		Uint16 offset = SDL_ReadLE16(rw);
-		Uint16 length = SDL_ReadLE16(rw);
+		Uint16 dataOffset = SDL_ReadLE16(rw);
+		Uint16 dataLength = SDL_ReadLE16(rw);
 		/* Uint16 flags = */ SDL_ReadLE16(rw);
-		Uint16 id = SDL_ReadLE16(rw);
+		Uint16 resourceID = SDL_ReadLE16(rw);
 		SDL_ReadLE32(rw); // reserved
 
-		id &= 0x7FFF;
-		if (id >= Cards_Count) continue;
+		resourceID &= 0x7FFF;
+		if (resourceID >= count) continue;
 
-		Sint64 next = SDL_RWtell(rw);
-		if (next < 0) return -1;
+		Sint64 nextResource = SDL_RWtell(rw);
+		if (nextResource < 0) return -1;
 
-		cards->surfaces[id] = dibSurface(
+		surfaces[resourceID] = dibSurface(
 			rw,
-			(Uint32)offset << alignmentShift,
-			(Uint32)length << alignmentShift
+			(Uint32)dataOffset << alignmentShift,
+			(Uint32)dataLength << alignmentShift
 		);
-		if (!cards->surfaces[id]) return -1;
+		if (!surfaces[resourceID]) return -1;
 
-		if (SDL_RWseek(rw, next, RW_SEEK_SET) < 0) 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(struct Cards *cards, SDL_RWops *rw, Uint16 peOffset) {
+static int
+loadPE(SDL_Surface **surfaces, size_t count, SDL_RWops *rw, Uint16 peOffset) {
 	if (SDL_RWseek(rw, peOffset + 0x04 + 0x02, RW_SEEK_SET) < 0) return -1;
 	Uint16 sectionCount = SDL_ReadLE16(rw);
 
@@ -254,7 +256,7 @@ static int loadPE(struct Cards *cards, SDL_RWops *rw, Uint16 peOffset) {
 	for (Uint16 i = 0; i < nameIDCount; ++i) {
 		Uint32 nameID = SDL_ReadLE32(rw);
 		Uint32 subdirOffset = SDL_ReadLE32(rw);
-		if (nameID >= Cards_Count) continue;
+		if (nameID >= count) continue;
 		if (!(subdirOffset & (1 << 31))) {
 			SDL_SetError("bitmap name entry does not point to table");
 			return -1;
@@ -288,8 +290,8 @@ static int loadPE(struct Cards *cards, SDL_RWops *rw, Uint16 peOffset) {
 		Uint32 dataOffset =
 			dataVirtual - (resourceTableVirtual - resourceTableOffset);
 
-		cards->surfaces[nameID] = dibSurface(rw, dataOffset, dataLength);
-		if (!cards->surfaces[nameID]) return -1;
+		surfaces[nameID] = dibSurface(rw, dataOffset, dataLength);
+		if (!surfaces[nameID]) return -1;
 
 		if (SDL_RWseek(rw, nextName, RW_SEEK_SET) < 0) return -1;
 	}
@@ -297,34 +299,38 @@ static int loadPE(struct Cards *cards, SDL_RWops *rw, Uint16 peOffset) {
 	return 0;
 }
 
-struct Cards *Cards_Load(SDL_RWops *rw, enum Cards_Flags flags) {
-	struct Cards *cards = calloc(1, sizeof(*cards));
-	if (!cards) {
-		SDL_SetError("calloc error: %s", strerror(errno));
-		return NULL;
-	}
-
-	if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0) goto fail;
+static int loadEXE(SDL_Surface **surfaces, size_t count, SDL_RWops *rw) {
+	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");
-		goto fail;
+		return -1;
 	}
 
-	if (SDL_RWseek(rw, 0x3C, RW_SEEK_SET) < 0) goto fail;
+	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) goto fail;
-	Uint8 sig[] = { SDL_ReadU8(rw), SDL_ReadU8(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') {
-		if (loadNE(cards, rw, offset) < 0) goto fail;
+		return loadNE(surfaces, count, rw, offset);
 	} else if (sig[0] == 'P' && sig[1] == 'E') {
-		if (loadPE(cards, rw, offset) < 0) goto fail;
+		return loadPE(surfaces, count, rw, offset);
 	} else {
 		SDL_SetError("invalid NE/PE signature");
-		goto fail;
+		return -1;
+	}
+}
+
+struct Cards *Cards_Load(SDL_RWops *rw, enum Cards_Flags flags) {
+	struct Cards *cards = calloc(1, sizeof(*cards));
+	if (!cards) {
+		SDL_SetError("calloc error: %s", strerror(errno));
+		return NULL;
 	}
 
+	if (loadEXE(cards->surfaces, Cards_Count, rw) < 0) goto fail;
+
 	for (int i = Cards_Club + Cards_A; i <= Cards_Spade + Cards_K; ++i) {
 		if (cards->surfaces[i]) continue;
 		SDL_SetError("missing resource %d", i);