|
from __future__ import print_function |
|
import unittest |
|
import collections |
|
import struct |
|
import sqlite3 |
|
import svgwrite |
|
|
|
|
|
''' |
|
vertex test cases: |
|
(10, FileLump(filepos=94972, size=1868, name='VERTEXES')) |
|
(21, FileLump(filepos=179996, size=3768, name='VERTEXES')) |
|
(32, FileLump(filepos=295644, size=3784, name='VERTEXES')) |
|
(43, FileLump(filepos=394692, size=3120, name='VERTEXES')) |
|
(54, FileLump(filepos=482536, size=2984, name='VERTEXES')) |
|
(65, FileLump(filepos=601156, size=4828, name='VERTEXES')) |
|
(76, FileLump(filepos=731496, size=3584, name='VERTEXES')) |
|
(87, FileLump(filepos=804588, size=1312, name='VERTEXES')) |
|
(98, FileLump(filepos=879156, size=2324, name='VERTEXES')) |
|
''' |
|
|
|
class IncorrectByteLength(Exception): |
|
def __init__(self, message="Not correct byte count"): |
|
super(IncorrectByteLength, self).__init__(message=message) |
|
|
|
Header = collections.namedtuple("Header", ['identification', |
|
'num_lumps', |
|
'info_table_offset']) |
|
|
|
|
|
|
|
def read_file(file_obj, size, handler, position=None): |
|
if position: |
|
file_obj.seek(position) |
|
datum = file_obj.read(size) |
|
if not datum: |
|
return None |
|
return handler(datum) |
|
|
|
|
|
def convert_file_header(data): |
|
# type: ([byte]) -> Header |
|
""" |
|
typedef struct |
|
{ |
|
// Should be "IWAD" or "PWAD". |
|
char identification[4]; |
|
int numlumps; |
|
int infotableofs; |
|
} PACKEDATTR wadinfo_t; |
|
""" |
|
if len(data) != 12: |
|
raise IncorrectByteLength("byte length {} instead of 12".format(len(data))) |
|
|
|
values = struct.unpack("<4sII", data) |
|
name, numlumps, info_table_offset = values |
|
return Header(name, |
|
numlumps, |
|
info_table_offset) |
|
|
|
|
|
FileLump = collections.namedtuple("FileLump", ['filepos', |
|
'size', |
|
'name']) |
|
|
|
|
|
|
|
def convert_filelump(data): |
|
# type: ([byte]) -> FileLump |
|
""" |
|
typedef struct |
|
{ |
|
int filepos; |
|
int size; |
|
char name[8]; |
|
} PACKEDATTR filelump_t; |
|
""" |
|
try: |
|
filepos, size, name = struct.unpack("<II8s", data) |
|
except Exception: |
|
raise |
|
return FileLump(filepos, size, name) |
|
|
|
LumpInfo = collections.namedtuple("LumpInfo", ['position', |
|
'size', |
|
'name', |
|
'wad_file']) |
|
|
|
|
|
def convert_lumpinfo(wad_file_name, file_lump): |
|
# type: (FileLump) -> LumpInfo |
|
return LumpInfo(file_lump.filepos, |
|
file_lump.size, |
|
file_lump.name, |
|
wad_file_name) |
|
|
|
|
|
|
|
Vertex = collections.namedtuple("Vertex", ["x","y"]) |
|
|
|
def read_vertex(data): |
|
# type: ([byte]) -> Vertex |
|
""" |
|
typedef struct |
|
{ |
|
short x; |
|
short y; |
|
} PACKEDATTR mapvertex_t; |
|
""" |
|
try: |
|
x, y = struct.unpack("<hh", data) |
|
except Exception: |
|
print("DDD", data) |
|
raise |
|
return Vertex(x,y) |
|
|
|
def create_schema_vertex(conn): |
|
create_schema = """ |
|
CREATE TABLE IF NOT EXISTS Vertex( |
|
idVertex INTEGER PRIMARY KEY, |
|
x, y INTEGER |
|
); |
|
""" |
|
delete_schema = """ |
|
DROP TABLE IF EXISTS Vertex; |
|
""" |
|
conn.execute(delete_schema) |
|
conn.execute(create_schema) |
|
|
|
def insert_vertex(conn, index, x, y): |
|
conn.execute(""" |
|
INSERT INTO Vertex(idVertex, x, y) VALUES (?, ?, ?); |
|
""", (index, x, y)) |
|
|
|
def split_file(file_obj, size): |
|
while True: |
|
data = file_obj.read(size) |
|
#print(data) |
|
if not data: |
|
break |
|
yield data |
|
|
|
MapLinedef = collections.namedtuple("MapLinedef", [ 'v1', |
|
'v2', |
|
'flags', |
|
'special', |
|
'tag', |
|
'sidenum' ]) |
|
|
|
def create_schema_linedef(conn): |
|
create_schema = """ |
|
CREATE TABLE IF NOT EXISTS LineDef ( |
|
-- idLineDef INTEGER PRIMARY KEY, |
|
vertex1 INTEGER, |
|
vertex2 INTEGER, |
|
flags INTEGER(2), |
|
-- sidenum left out for now. |
|
FOREIGN KEY(vertex1) REFERENCES Vertex(idVertex), |
|
FOREIGN KEY(vertex2) REFERENCES Vertex(idVertex) |
|
); |
|
""" |
|
|
|
delete_schema = """ |
|
DROP TABLE IF EXISTS LineDef; |
|
""" |
|
conn.execute(delete_schema) |
|
conn.execute(create_schema) |
|
|
|
|
|
|
|
def insert_linedef(conn, vertex1, vertex2): |
|
conn.execute(""" |
|
INSERT INTO LineDef(vertex1, vertex2) VALUES (?, ?); |
|
""", (vertex1, vertex2)) |
|
|
|
def read_maplinedef(data): |
|
# type: ([byte]) -> MapLinedef |
|
""" |
|
typedef struct |
|
{ |
|
short v1; //2 |
|
short v2; //2 |
|
short flags; //2 |
|
short special; //2 |
|
short tag; //2 |
|
// sidenum[1] will be -1 if one sided |
|
short sidenum[2]; //4 |
|
# } PACKEDATTR maplinedef_t; |
|
""" |
|
sidenum = [-1, -1] |
|
try: |
|
v1, v2, flags, tag, special, sidenum[0], sidenum[1] = struct.unpack("<hhhhhhh", data) |
|
except Exception: |
|
raise |
|
return MapLinedef(v1, v2, flags, tag, special, [sidenum[0], sidenum[1]]) |
|
|
|
class TestWad(unittest.TestCase): |
|
|
|
def test_add_file(self): |
|
# need to make custom wad for tests... |
|
test_file_name = 'doom1.wad' |
|
import pdb; pdb.set_trace() |
|
with open(test_file_name, 'rb') as file_data: |
|
header = read_file(file_data, |
|
12, |
|
convert_file_header) |
|
|
|
# Go to the position where the actually starts |
|
file_data.seek(header.info_table_offset) |
|
|
|
# LAZY LIZZARD!!! |
|
# split file into 16 byte chunks |
|
file_lumps = (convert_filelump(i) for i in split_file(file_data, 16)) |
|
|
|
lump_info = list(convert_lumpinfo(test_file_name, i) for i in file_lumps) |
|
# map(print, enumerate(lump_info)) |
|
def read_lump(lump_self, index, struct_size=1): |
|
current_lump = lump_self[index] |
|
with open(current_lump.wad_file, 'rb') as wad_file_data: |
|
wad_file_data.seek(current_lump.position) |
|
bytes_left = current_lump.size |
|
while True: |
|
datum = wad_file_data.read(struct_size) |
|
if not datum: |
|
break |
|
|
|
if bytes_left <= 0: |
|
break |
|
|
|
bytes_left -= struct_size |
|
yield datum |
|
|
|
with sqlite3.connect("waddb.db") as conn: |
|
create_schema_vertex(conn) |
|
create_schema_linedef(conn) |
|
|
|
#vertexes are 4 bytes big in the file. |
|
for index, data in enumerate(read_lump(lump_info, 10, 4)): |
|
vertex = read_vertex(data) |
|
insert_vertex(conn, index, vertex.x, vertex.y) |
|
|
|
#linedefs are 14 bytes big in the file. |
|
for i in read_lump(lump_info, 8, 14): |
|
#print(read_maplinedef(i)) |
|
linedef = read_maplinedef(i) |
|
insert_linedef(conn, linedef.v1, linedef.v2) |