forked from K0lb3/UnityPy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWebFile.py
More file actions
122 lines (99 loc) · 3.03 KB
/
Copy pathWebFile.py
File metadata and controls
122 lines (99 loc) · 3.03 KB
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
import io
import os
from ..EndianBinaryReader import EndianBinaryReader
from ..EndianBinaryWriter import EndianBinaryWriter
from ..helpers import CompressionHelper
class WebFile:
files: list
compression: str
signature: str
"""A package which can hold other WebFiles, Bundles and SerialiedFiles.
It may be compressed via gzip or brotli.
files -- list of all files in the WebFile
"""
def __init__(self, reader: EndianBinaryReader):
self.files = []
magic = reader.read_bytes(2)
reader.Position = 0
if magic == CompressionHelper.GZIP_MAGIC:
self._compression = 'gzip'
data = CompressionHelper.decompress_gzip(reader.bytes)
binary_reader = EndianBinaryReader(data, endian='<')
self.reader_web_data(binary_reader)
else:
reader.Position = 0x20
magic = reader.read_bytes(6)
reader.Position = 0
if CompressionHelper.BROTLI_MAGIC == magic:
self._compression = 'brotli'
data = CompressionHelper.decompress_brotli(reader.bytes)
binary_reader = EndianBinaryReader(data, endian='<')
self.reader_web_data(binary_reader)
else:
self._compression = None
reader.endian = '<'
self.reader_web_data(reader)
def reader_web_data(self, reader: EndianBinaryReader):
"""Extracts the files saved in the WebFile."""
signature = reader.read_string_to_null()
if signature != "UnityWebData1.0":
return
head_length = reader.read_int()
while reader.Position < head_length:
self.files.append(WebData(reader))
for f in self.files:
f.read_data(reader)
def save(self) -> bytes:
files = self.files
writer = EndianBinaryWriter(endian="<")
# signature
writer.write_string_to_null(self.signature)
offset = sum([
writer.Position, # signature
sum(len(f.path.encode("utf8")) for f in files), # path of each file
4 * 3 * len(files), # 3 ints per file
4 # offset int
])
# head_length
writer.write_int(offset)
# 1. data list
for f in files:
offset = f.write(writer, offset)
# 2. data
for f in files:
writer.write(f.stream.getbuffer())
data = writer.bytes
if self.compression == "gzip":
data = CompressionHelper.compress_gzip(data)
elif self.compression == "brotli":
data = CompressionHelper.compress_brotli(data)
return data
class WebData:
offset: int
length: int
path: str
stream: io.BytesIO
def __init__(self, reader: EndianBinaryReader):
self.offset = reader.read_int()
self.length = reader.read_int()
path_length = reader.read_int()
self.path = reader.read_bytes(path_length).decode('utf8')
def write(self, writer: EndianBinaryWriter, offset) -> int:
# reverse of __init__
# returns increased offset
# offset
writer.write_int(offset)
# length
length = len(self.stream.getbuffer())
writer.write_int(length)
# path
enc_path = self.path.encode("utf8")
writer.write_int(len(enc_path))
writer.write(enc_path)
return offset + length
@property
def name(self):
return os.path.basename(self.path)
def read_data(self, reader: EndianBinaryReader):
reader.Position = self.offset
self.stream = io.BytesIO(reader.read(self.length))