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
117 lines (98 loc) · 3.56 KB
/
Copy pathWebFile.py
File metadata and controls
117 lines (98 loc) · 3.56 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
from typing import Optional
from ..helpers import CompressionHelper
from ..streams import EndianBinaryReader, EndianBinaryWriter
from . import File
class WebFile(File.File):
"""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, parent: File, name=None, **kwargs):
"""Constructor Method"""
super().__init__(parent=parent, name=name, **kwargs)
# check compression
magic = reader.read_bytes(2)
reader.Position = 0
if magic == CompressionHelper.GZIP_MAGIC:
self.packer = "gzip"
data = CompressionHelper.decompress_gzip(reader.bytes)
reader = EndianBinaryReader(data, endian="<")
else:
reader.Position = 0x20
magic = reader.read_bytes(6)
reader.Position = 0
if CompressionHelper.BROTLI_MAGIC == magic:
self.packer = "brotli"
data = CompressionHelper.decompress_brotli(reader.bytes)
reader = EndianBinaryReader(data, endian="<")
else:
self.packer = "none"
reader.endian = "<"
# signature check
signature = reader.read_string_to_null()
if not signature.startswith(("UnityWebData", "TuanjieWebData")):
return
self.signature = signature
# read header -> contains file headers
head_length = reader.read_int()
files = []
while reader.Position < head_length:
offset = reader.read_int()
length = reader.read_int()
path_length = reader.read_int()
name = bytes(reader.read_bytes(path_length)).decode("utf-8")
files.append(File.DirectoryInfo(name, offset, length))
self.read_files(reader, files)
def save(
self,
files: Optional[dict] = None,
packer: str = "none",
signature: str = "UnityWebData1.0",
) -> bytes:
# solve defaults
if not files:
files = self.files
if not packer:
packer = self.packer
# get raw data
files = {
name: f.bytes if isinstance(f, EndianBinaryReader) else f.save()
for name, f in files.items()
}
# create writer
writer = EndianBinaryWriter(endian="<")
# signature
writer.write_string_to_null(signature)
# data offset
offset = sum(
[
writer.Position, # signature
sum(
len(path.encode("utf-8")) for path in files.keys()
), # path of each file
4 * 3 * len(files), # 3 ints per file
4, # offset int
]
)
writer.write_int(offset)
# 1. file headers
for name, data in files.items():
# offset
writer.write_int(offset)
# length
length = len(data)
writer.write_int(length)
offset += length
# path
enc_path = name.encode("utf-8")
writer.write_int(len(enc_path))
writer.write(enc_path)
# 2. file data
for data in files.values():
writer.write(data)
if packer == "gzip":
return CompressionHelper.compress_gzip(writer.bytes)
elif packer == "brotli":
return CompressionHelper.compress_brotli(writer.bytes)
else:
return writer.bytes