diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | cards.c | 214 | ||||
-rw-r--r-- | cards.h | 52 | ||||
-rw-r--r-- | dump.c | 59 |
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); } |