diff options
author | June McEnroe <june@causal.agency> | 2019-03-25 22:39:05 -0400 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2019-03-25 22:39:05 -0400 |
commit | e14c98bd3670ef66bbdfd15e420c4e3159d262f4 (patch) | |
tree | f4b088f8f17ef2a74ebb848f629459815d0cf4ff | |
parent | Only set palette length for bitsPerPixel < 16 (diff) | |
download | cards-e14c98bd3670ef66bbdfd15e420c4e3159d262f4.tar.gz cards-e14c98bd3670ef66bbdfd15e420c4e3159d262f4.zip |
Implement loadPE
Can now load cards.dll from Windows XP.
-rw-r--r-- | cards.c | 104 |
1 files changed, 101 insertions, 3 deletions
diff --git a/cards.c b/cards.c index e67317d..174b081 100644 --- a/cards.c +++ b/cards.c @@ -171,7 +171,7 @@ 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); - SDL_ReadLE16(rw); // flags + /* Uint16 flags = */ SDL_ReadLE16(rw); Uint16 id = SDL_ReadLE16(rw); SDL_ReadLE32(rw); // reserved @@ -194,9 +194,107 @@ static int loadNE(struct Cards *cards, SDL_RWops *rw, Uint16 neOffset) { return 0; } +// <https://docs.microsoft.com/en-us/windows/desktop/Debug/pe-format> static int loadPE(struct Cards *cards, SDL_RWops *rw, Uint16 peOffset) { - SDL_SetError("loadPE unimplemented"); - return -1; + 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); + Uint32 subdirOffset = SDL_ReadLE32(rw); + if (nameID >= Cards_Count) continue; + 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); + + cards->surfaces[nameID] = dibSurface(rw, dataOffset, dataLength); + if (!cards->surfaces[nameID]) return -1; + + if (SDL_RWseek(rw, nextName, RW_SEEK_SET) < 0) return -1; + } + + return 0; } struct Cards *Cards_Load(SDL_RWops *rw, enum Cards_Flags flags) { |