Skip to content

Instantly share code, notes, and snippets.

@angea
Last active January 18, 2025 12:01
Show Gist options
  • Save angea/e039b0046328dd2ab730324e21c4401a to your computer and use it in GitHub Desktop.
Save angea/e039b0046328dd2ab730324e21c4401a to your computer and use it in GitHub Desktop.
Doom WAD tool
#!/usr/bin/env python3
# WadDump
import argparse
SIZE_MIN = 4 + 4 + 4
signatures = {
b"IWAD": "Wad",
b"PWAD": "Patch Wad",
}
LUMPS = {
b"BEHAVIOR" : "Behavior",
b"BLOCKMAP" : "Blockmap",
b"DIALOGUE" : "Dialogue",
b"ENDMAP" : "Endmap" ,
b"LINEDEFS" : "Linedefs",
b"NODES" : "Nodes" ,
b"REJECT" : "Reject" ,
b"SCRIPTS" : "Scripts" ,
b"SECTORS" : "Sectors" ,
b"SEGS" : "Segments",
b"SIDEDEFS" : "Sidedefs",
b"SSECTORS" : "SubSsectors",
b"TEXTMAP" : "Textmap" ,
b"THINGS" : "Things" ,
b"VERTEXES" : "Vertexes",
b"ZNODES" : "Znodes" ,
b"LEADS" : "Leafs",
b"MACROS" : "Macros",
# Sonic Robo Blast 2
b"SOC*" : "Sonic Object Configuration",
b"LUA_SOC_START" : "Sonic Object Configuration",
b"S_START": "Sprites",
b"S_END": "Sprites",
b"SS_START": "Sprites",
b"SS_END": "Sprites",
b"F_START": "Flats",
b"F_END": "Flats",
b"FF_START": "Flats",
b"FF_END": "Flats",
b"TX_START": "Textures",
b"TX_END": "Textures",
b"P_START": "Texture patches",
b"P_END": "Texture patches",
b"GX_START": "HUD graphics",
b"GX_END": "HUD graphics",
b"C_START": "Color maps",
b"C_END": "Color maps",
}
def b2h(s):
return " ".join("%02X" % c for c in s)
def parse_file(data):
if len(data) < SIZE_MIN:
print("Error: file too small")
return
cursor = 0
signature = data[cursor:cursor + 4]
cursor += 4
if signature not in signatures:
print("Error: Invalid signature")
return
print("Signature: %s" % (signatures[signature]))
count = int.from_bytes(data[cursor: cursor + 4], byteorder = "little")
cursor += 4
print("Lump count: %i" % count)
offset = int.from_bytes(data[cursor: cursor + 4], byteorder = "little")
cursor += 4
print("Directory offset: %08X" % offset)
if offset > len(data):
print("Error: Offset too big")
return
if offset + count * (4 + 4 + 8) > len(data):
print("Error: Offset + count too big")
return
cursor = offset
for i in range(count):
offset = int.from_bytes(data[cursor: cursor + 4], byteorder = "little")
cursor += 4
size = int.from_bytes(data[cursor: cursor + 4], byteorder = "little")
cursor += 4
lumpname = data[cursor: cursor + 8].rstrip(b"\0")
cursor += 8
if size == 0:
if lumpname in LUMPS:
contents = LUMPS[lumpname]
else:
contents = ""
elif size <= 8:
contents = b2h(data[offset: offset + size])
else:
contents = "%s....%s" % (b2h(data[offset:offset + 8]), b2h(data[offset + size -8:offset + size]))
print("%03i/%03i: %08x:+%08X %s %s" % (i, count, offset, size, lumpname.decode().ljust(8), contents))
parser = argparse.ArgumentParser(
prog='Wad Dump', description='WAD (Doom-like) file dumper')
parser.add_argument('filename', help='wad file')
args = parser.parse_args()
fn = args.filename
with open(fn, "rb") as f:
data = f.read()
parse_file(data)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment