-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaddon.py
106 lines (89 loc) · 2.79 KB
/
addon.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
import json
MAX_VER = 3
class FileEntry:
def __init__(self, addon):
self.addon = addon
self.name = ""
self.size = 0
self.CRC = 0
self.offset = 0
def save(self, path):
block_size = 2**12
writed = 0
self.addon.file.seek(self.addon.file_block)
self.addon.file.seek(self.offset, 1)
with open(path, "wb") as file:
while writed < self.size:
if block_size > self.size - writed:
block_size = self.size - writed
file.write(self.addon.file.read(block_size))
writed += block_size
class Addon:
def __init__(self, path):
self.path = path
self.file = None
self.format_ver = 0
self.name = ""
self.desc = ""
self.type = ""
self.tags = []
self.author = ""
self.version = 0
self.file_block = 0
self.entries = []
def open(self):
self.file = open(self.path, "rb")
def check_file(self):
gmad = self.read_buff(4)
if gmad != b"GMAD":
return False
self.format_ver = self.read_int(1)
if self.format_ver > MAX_VER:
return False
return True
def parse(self):
self.read_buff(16) # steamid & timestamp
if self.format_ver > 1:
while self.read_str(): pass
self.name = self.read_str()
self.desc = self.read_str()
self.author = self.read_str()
self.version = self.read_int(4, True)
self.desc = json.loads(self.desc)
self.type = self.desc["type"]
self.tags = self.desc["tags"]
self.desc = self.desc["description"]
def get_entries(self):
offset = 0
while self.read_int(4):
entry = FileEntry(self)
entry.name = self.read_str()
entry.size = self.read_int(8)
entry.CRC = self.read_int(4)
entry.offset = offset
offset += entry.size
self.entries.append(entry)
self.file_block = self.file.tell()
def read_buff(self, size):
buff = self.file.read(size)
if len(buff) != size:
raise ValueError("readed %d instead of %s" % (len(buff), size))
return buff
def read_int(self, size, signed = False):
buff = self.read_buff(size)
return int.from_bytes(buff, "little", signed = signed)
def read_str(self):
buff = b""
c = self.file.read(1)
while c != b"\0":
buff += c
c = self.file.read(1)
return buff.decode()
def load(path):
addon = Addon(path)
addon.open()
if not addon.check_file():
raise TypeError("wrong file type")
addon.parse()
addon.get_entries()
return addon