SHOW:
|
|
- or go back to the newest paste.
1 | /* | |
2 | * Filename: RARCTemplate.bt | |
3 | * Last Modified: 2014-06-12 | |
4 | * Author: Phillip "Antidote" Michael Thomas Stephens | |
5 | * Purpose: J3D Engine Archives (RARC) | |
6 | * License: GPLv2 | |
7 | * 010 Version: >= 5.0 | |
8 | */ | |
9 | BigEndian(); | |
10 | ||
11 | struct FileDescriptor | |
12 | { | |
13 | - | ushort ID; |
13 | + | // All "files" have an ID, it can be used to create a find by ID function |
14 | - | ushort Unknown1 <format = hex>; |
14 | + | // rather than searching by name, iirc it corresponds with the file number used in |
15 | - | ushort Unknown2 <format = hex>; |
15 | + | // STB files, I think I confirmed this a while back but I'm not entirely sure |
16 | - | ushort FilenameOffset; |
16 | + | ushort ID; |
17 | - | uint DataStart <format = hex>; |
17 | + | // The next value appears to be a sort of hash, if it's a directory node and NOT "." or "..", |
18 | - | uint DataSize <format = hex>; |
18 | + | // it matches it's corresponding node in the node table, not sure of it's purpose, |
19 | - | uint Zero; |
19 | + | // changing it's value does nothing of merit |
20 | ushort Unknown1 <format = hex>; | |
21 | // Not sure what this one is | |
22 | ushort Unknown2 <format = hex>; | |
23 | ushort FilenameOffset; | |
24 | - | char Type[4]; |
24 | + | uint DataStart <format = hex>; |
25 | - | uint FilenameOffset; |
25 | + | uint DataSize <format = hex>; |
26 | - | ushort Unknown <format = hex>; |
26 | + | uint Zero; |
27 | - | ushort FileEntryCount; |
27 | + | |
28 | - | uint FirstFileStart; |
28 | + | |
29 | struct Node | |
30 | { | |
31 | // Kind of misleading, it's not really a Type descriptor, | |
32 | // it's more of a 4 letter uppercase version of the directories name. | |
33 | - | FileDescriptor Descriptor; |
33 | + | char Type[4]; |
34 | - | local int tmp = FTell(); |
34 | + | uint FilenameOffset; |
35 | - | FSeek((file.StringTableStart + file.HeaderSize) + Descriptor.FilenameOffset); |
35 | + | // Read the above notation for Unknown1 in FileDescriptor |
36 | - | string Filename; |
36 | + | ushort Unknown <format = hex>; |
37 | - | FSeek(tmp); |
37 | + | ushort FileEntryCount; |
38 | - | if (Descriptor.ID == 0xFFFF && Filename != "." && Filename != "..") |
38 | + | uint FirstFileStart; |
39 | - | { |
39 | + | |
40 | - | FSeek(file.FileEntriesStart + (file.Nodes[Descriptor.DataStart].FirstFileStart * sizeof(FileDescriptor)) + 0x20); |
40 | + | |
41 | - | FileEntry FileEntries[file.Nodes[Descriptor.DataStart].FileEntryCount] <optimize = false>; |
41 | + | |
42 | - | FSeek(tmp); |
42 | + | |
43 | - | } |
43 | + | |
44 | - | else if (Filename != "." && Filename != "..") |
44 | + | FileDescriptor Descriptor; |
45 | - | { |
45 | + | local int tmp = FTell(); |
46 | - | FSeek(file.DataStart + Descriptor.DataStart + 0x20); |
46 | + | FSeek((file.StringTableStart + file.HeaderSize) + Descriptor.FilenameOffset); |
47 | - | ubyte Data[Descriptor.DataSize]; |
47 | + | string Filename; |
48 | - | FSeek(tmp); |
48 | + | FSeek(tmp); |
49 | - | } |
49 | + | // If the descriptor's ID is 0xFFFF it's a directory, otherwise it's a file |
50 | if (Descriptor.ID == 0xFFFF && Filename != "." && Filename != "..") | |
51 | { | |
52 | // If we're a directory AND we're not "." or ".." we read in our children | |
53 | FSeek(file.FileEntriesStart + (file.Nodes[Descriptor.DataStart].FirstFileStart * sizeof(FileDescriptor)) + 0x20); | |
54 | - | uint Magic <format = hex>; |
54 | + | FileEntry FileEntries[file.Nodes[Descriptor.DataStart].FileEntryCount] <optimize = false>; |
55 | - | if (Magic != 0x52415243) |
55 | + | FSeek(tmp); |
56 | - | { |
56 | + | // The reason we don't want to handle "." and ".." is because of a known quirk in computers, |
57 | - | Warning("Not a valid RARC File"); |
57 | + | // I won't elaborate but here is a link on the issue: |
58 | - | return; |
58 | + | // http://stackoverflow.com/questions/2630054/does-c-limit-recursion-depth |
59 | - | } |
59 | + | // I.E, blame the stack implementation :P |
60 | - | uint FileSize <format = hex>; |
60 | + | } |
61 | - | if (FileSize != FileSize()) |
61 | + | else if (Filename != "." && Filename != "..") |
62 | - | { |
62 | + | { |
63 | - | Warning("Malformed file, stored size does not match actual size"); |
63 | + | FSeek(file.DataStart + Descriptor.DataStart + 0x20); |
64 | - | return; |
64 | + | ubyte Data[Descriptor.DataSize]; |
65 | - | } |
65 | + | FSeek(tmp); |
66 | - | uint HeaderSize; |
66 | + | } |
67 | - | uint DataStart <format = hex>; |
67 | + | |
68 | - | uint Unknown[4] <format = hex>; |
68 | + | |
69 | - | uint NodeCount; |
69 | + | |
70 | - | uint Unknown2[2] <format = hex>; |
70 | + | |
71 | - | uint FileEntriesStart <format = hex>; |
71 | + | // The archive's Magic, must always be "RARC", if it's "Yaz0" it's "compressed" |
72 | - | uint StringTableSize <format = hex>; |
72 | + | uint Magic <format = hex>; |
73 | - | uint StringTableStart <format = hex>; |
73 | + | if (Magic != 0x52415243) |
74 | - | uint Unknown4[2] <format = hex>; |
74 | + | { |
75 | Warning("Not a valid RARC File"); | |
76 | - | Node Nodes[NodeCount] <optimize = false>; |
76 | + | return; |
77 | - | local int tmp = FTell(); |
77 | + | } |
78 | - | FSeek(FileEntriesStart + Nodes[0].FirstFileStart + 0x20); |
78 | + | // This value MUST equal the total size of the file, if it doesn't the game will reject it |
79 | - | FileEntry FileEntries[Nodes[0].FileEntryCount] <optimize = false>; |
79 | + | // if it's a vital archive the game will hang, otherwise the data simply won't be loaded |
80 | - | FSeek(tmp); |
80 | + | uint FileSize <format = hex>; |
81 | if (FileSize != FileSize()) | |
82 | { | |
83 | Warning("Malformed file, stored size does not match actual size"); | |
84 | return; | |
85 | } | |
86 | uint HeaderSize; | |
87 | uint DataStart <format = hex>; | |
88 | // Appears to be a series of offsets, they do nothing of merit | |
89 | uint Unknown[4] <format = hex>; | |
90 | uint NodeCount; | |
91 | // These appear to be counts of some sort, again they do nothing of merit. | |
92 | uint Unknown2[2] <format = hex>; | |
93 | uint FileEntriesStart <format = hex>; | |
94 | uint StringTableSize <format = hex>; | |
95 | uint StringTableStart <format = hex>; | |
96 | uint Unknown4[2] <format = hex>; | |
97 | ||
98 | Node Nodes[NodeCount] <optimize = false>; | |
99 | local int tmp = FTell(); | |
100 | FSeek(FileEntriesStart + Nodes[0].FirstFileStart + 0x20); | |
101 | FileEntry FileEntries[Nodes[0].FileEntryCount] <optimize = false>; | |
102 | FSeek(tmp); | |
103 | }file; |