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; |