-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEX_Filelist_v4-7.bt
More file actions
219 lines (181 loc) · 5.4 KB
/
EX_Filelist_v4-7.bt
File metadata and controls
219 lines (181 loc) · 5.4 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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
//------------------------------------------------
//--- 010 Editor v14.0 Binary Template
//
// File: EngineX filelist descriptor (.bin)
// Authors: Ebbe (with heavy inspiration from Swyter's documentation)
// Version: 2025-09-05
// Purpose: Decode the descriptor file used in Eurocom's EngineX
// titles to index the data in the filelist.
// For use in filelist versions 4, 5, 6 and 7.
// Category: Game
// File Mask: *.bin
//------------------------------------------------
// Scratch counting variables
local int i = 0;
local int j = 0;
// Helper struct for relative pointers.
// Absolute address is their own address + the offset they store.
typedef struct
{
// Relative offset
int rpOffset<format=hex>;
// Absolute offset
local uint AbsOffset<format=hex> = rpOffset == 0 ? 0 : FTell() - 4 + rpOffset;
} RelPtr
<read=Str("%s",
rpOffset == 0 ?
"null" :
Str("Rel: 0x%x, Abs: 0x%x", rpOffset, AbsOffset)
), optimize=false>;
/*
* If the first two bytes contain data, it likely means the file is
* little endian, since the version number would only be in the least
* significant byte.
*/
local uint endianTest = ReadUShort();
(endianTest == 0) ? BigEndian() : LittleEndian();
// Grab the version now for later use.
local uint ver = ReadUInt();
// Check if the template supports it.
if (
(ver != 4) &&
(ver != 5) &&
(ver != 6) &&
(ver != 7)
) {
Warning("Unsupported Filelist version: %u", ver);
Exit(-1);
}
// Filelist Header
typedef struct
{
uint Version;
uint FileSize<format=hex>;
uint NumFiles;
if (ver >= 5) {
// 0 if files are stored loosely outside the
// virtual filesystem, 1 if not.
ushort BuildType;
// v4 has all the data in a single .dat file.
// v5+ can have multiple archives, labelled .000, .001 etc.
ushort NumFileLists;
}
// Offset to table of file name offsets.
RelPtr FileNameListOffset;
} FILELIST_HEADER
<read=Str("Version: %d, NumFiles: %d%s", Version, NumFiles,
ver >= 5 ? Str(", Filelists: %d", NumFileLists+1) : ""),
optimize=false,
bgcolor=0xFF6060>;
FILELIST_HEADER Header;
//Save address for later
local uint fileInfoStartAddr = FTell();
/*
* We jump ahead to the filename strings to build up an
* array of them so we can reference it later when reading
* the file info elements themselves.
*/
FSeek(Header.FileNameListOffset.AbsOffset);
RelPtr FileNameList[Header.NumFiles] <bgcolor=0x60C060>;
local char currByte = 0;
struct {
// Iterate through all files.
for (i = 0; i < Header.NumFiles; i++) {
// Seek to the string data.
FSeek(FileNameList[i].AbsOffset);
struct {
local string Str = "";
// Loop until we hit a terminator.
for (j = 0; true; j++) {
currByte = ReadByte(FTell() + j);
/*
* Version 7+ "encrypts" the text byte-for-byte using a simple cypher:
* Encrypted char = Normal char - 0x16 + File index + Char index
*
* We simply reverse the process here.
*/
if (ver >= 7) {
currByte = currByte + 0x16 - i - j;
}
// Check for null terminator
if (currByte == 0) {
break;
}
Str += currByte;
}
char Chars[j+1];
} FileName <read=Str, optimize=false>;
}
} FileNames
<read=Str("Encrypted: %s", ver >= 7 ? "Yes" : "No"),
optimize=false,
bgcolor=0x60FF60>;
// Seek back to the start of the file info table.
FSeek(fileInfoStartAddr);
typedef struct
{
// Location of file in bytes.
uint FileLoc<format=hex>;
// Filelist file to reference (v5+)
uint FileListNum;
} FILE_LOC_INFO
<read=Str("Location: 0x%x, Filelist: %d", FileLoc, FileListNum),
optimize=false>;
i = 0; // To keep track of current file index.
typedef struct
{
// Grab the path string for this file.
local string Path = FileNames.FileName[i].Str;
i++;
// Since v4 filelists use a single .dat binary file,
// files simply store a single offset into it here.
if (ver <= 4) {
uint FileLoc<format=hex>;
}
/*
* Length of the file in bytes.
*
* BE AWARE: For .edb files this will only report the minimum "base" file size.
* The actual file size can be found at offset 0x14 into the .edb file's header.
*/
uint Length<format=hex>;
uint HashCode<format=hex>;
// File version. Should match the version specified by the file itself, if it has one.
uint Version;
uint Flags<format=hex>;
/*
* v5+ filelists support multiple filelists, so they have an array of elements
* describing their location and which filelist they're in.
*
* Normally a file only has 1 location, but they can have multiple
* (to optimize for disk seeking time).
*/
if (ver >= 5) {
uint NumFileLoc;
if (NumFileLoc > 0) {
FILE_LOC_INFO FileLocInfo[NumFileLoc];
}
}
} FILE_INFO
<read=Str("%s", Path),
optimize=false>;
FILE_INFO FileInfo[Header.NumFiles] <bgcolor=0xFFA0B0>;
// Replicate the output by the XUtil generator in the console.
for (i = 0; i<Header.NumFiles; i++) {
Printf("%-72s : Len %10u : Ver %4u : Hash 0x%08x : Ts 0x%08x : Loc %s\r\n",
FileNames.FileName[i].Str != "" ? FileNames.FileName[i].Str : " *??? <missing path>",
FileInfo[i].Length,
FileInfo[i].Version,
FileInfo[i].HashCode,
FileInfo[i].Flags,
ver >= 5 ? // Check if referencing single .dat file or multiple .000, .001 (etc) files
(
FileInfo[i].NumFileLoc == 0 ? // Check if any file location referenced
"<no location>" :
Str("%11x:%03x",
FileInfo[i].FileLocInfo[0].FileLoc, // Just pick whatever is first
FileInfo[i].FileLocInfo[0].FileListNum
)
) :
Str("%11x", FileInfo[i].FileLoc));
}