/
decode.py
145 lines (122 loc) · 5.27 KB
/
decode.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
from core import *
from progress import dummy_callback
import merge
import re, os, itertools
def decode_file(path):
''' Parses a raw file and returns a list of the objects in it '''
fname = os.path.split(path)[-1]
objects = []
data = open(path, 'rt').read().decode('cp437')
pat = re.compile(r'\[([^\[\]]+):([^\[\]]+)\]')
match = pat.search(data)
if not match or match.group(1) != 'OBJECT':
raise Exception('No [OBJECT:<type>] tag found when parsing file %s' % path)
root_type = match.group(2)
match2 = pat.search(data, pos=match.end())
if not match2:
return []
type = match2.group(1)
split = re.split(r'\[%s:([^\[\]]+)\]' % type, data)[1:]
comment = ''
for name, raw_data in itertools.izip(
itertools.islice(split, 0, None, 2),
itertools.islice(split, 1, None, 2)):
raw_data = raw_data.strip('\n') # Strip extra newlines from start/end
if comment:
raw_data = comment + '\n' + raw_data
comment = ''
before_last_tag, sep, extra_stuff = raw_data.rpartition(']')
if sep and extra_stuff.strip():
comment = extra_stuff.strip()
raw_data = before_last_tag + sep
object = Object(fname, type, root_type, name)
object.extra_data = raw_data
objects.append(object)
return objects
def decode_directory(path, callback=dummy_callback):
''' Parses all files in a directory as raw files and returns all the objects '''
objects = []
files = [f for f in sorted(os.listdir(path)) if f.endswith('.txt') and 'readme' not in f.lower()]
callback.set_task_number(len(files))
for f in files:
callback.task_started(label=f)
objects.extend(decode_file(os.path.join(path, f)))
callback.done()
return DataSet(objects, included_files=os.listdir(path))
def decode_core():
return decode_directory('core')
def get_mod_list():
return [f for f in os.listdir('mods') if f.endswith('.dfmod')]
def decode_mod_headers(path):
''' Returns only the header information from the mod as a dictionary '''
d = {}
if hasattr(path, 'read'):
f = path
else:
f = open(path, 'rt')
for line in f:
if '!DFMM' not in line:
return False
dfmm, keyword, value = line.strip().split('|', 2)
if keyword in ['ADD', 'MODIFY', 'DELETE']:
# We have reached the end of the header; now we have a "real" command
return d
else:
d[keyword.lower()] = value
return d
def decode_mod(path, base_dataset):
if hasattr(path, 'read'):
f = path
else:
f = open(path, 'rt')
commands = f.read().decode('cp437').split('!DFMM')[1:]
for command in commands:
dfmm, keyword, value = command.strip().split('|', 2)
if keyword == 'NAME':
mod = Mod(value, path, base_dataset, [])
continue
if keyword not in ['ADD', 'MODIFY', 'DELETE']:
continue
dfmm, keyword, filename, root_type, type, name, patch_data = command.strip().split('|', 6)
o = Object(filename, type, root_type, name)
if keyword == 'ADD':
o.extra_data = patch_data
o.added = True
elif keyword == 'MODIFY':
try:
core_object = base_dataset.get_object(o.root_type,o.type, o.name)
if not core_object:
print 'Error decoding modification to object [%s:%s] in mod %s: object does not exist. Skipping.' % (o.type, o.name, path)
continue
else:
# Add the ampersand on the front to prevent stripping of initial tab, if any
results = merge.apply_patch_text('&'+core_object.extra_data, patch_data)
n = results[1].count(False)
t = len(results[1])
if n != 0:
print 'Warning: %d/%d modifications to object [%s:%s] in mod %s could not be applied and have been skipped.' % (n, t, o.type, o.name, path)
o.extra_data = results[0][1:] # Remove ampersand
o.patch_cache = patch_data # Save patch data for faster save
except:
print 'Error decoding modification to object [%s:%s] in mod %s. Skipping.' % (o.type, o.name, path)
continue
o.modified = True
elif keyword == 'DELETE':
o.deleted = True
else:
continue
mod.objects.append(o)
return mod
if __name__ == '__main__':
#objects = decode_file('raw/objects/inorganic_stone_layer.txt')
#import cProfile
#cProfile.run('decode_directory("core")','out.dat')
#print len(objects)
#print objects[0].extra_data
core_dataset = decode_core()
#print decode_mod('mods2/genesis.dfmod', core_dataset)
#print decode_file('core/item_food.txt')
print verify_mod_checksum('mods/genesis.dfmod', core_dataset)
#print decode_all_mods()
#defense_dataset = decode_directory('defense')
#print core_dataset.difference(defense_dataset)