cl3.md (3912B)
1 CL3 2 === 3 4 CL3 is an archive format, that contains uncompressed files plus links between 5 them. All integers are little-endian. Offsets are 0x40 bytes aligned in the 6 original files (this is not a requirement). 7 8 Header 9 ------ 10 11 ```c++ 12 struct Header 13 { 14 char magic[3]; // always "CL3" 15 char endian; 16 uint32_t field_04; // always 0 17 uint32_t field_08; // always 3 18 uint32_t sections_count; 19 uint32_t sections_offset; 20 uint32_t field_14; 21 // maybe more? 22 }; 23 sizeof(Header) == 0x18 24 ``` 25 26 `endian` is `L` if the file is little-endian, `B` if big-endian. `field_14` is 27 either 0, 1 or 2 (at least in RB3). Script `.cl3`s use 1, effect `.cl3`s use 2. 28 29 Sections 30 -------- 31 32 Starting at `sections_offset` (relative to file beginning), there are 33 `sections_count` sections. 34 35 ```c++ 36 struct Section 37 { 38 char name[0x20]; // '\0' terminated 39 uint32_t count; 40 uint32_t data_size; 41 uint32_t data_offset; 42 uint32_t padding[9]; // always 0 43 }; 44 sizeof(Section) == 0x50 45 ``` 46 47 There are two known sections: `FILE_COLLECTION` and `FILE_LINK`. Each has a 48 payload of `data_size` bytes starting at `data_offset`. 49 50 FILE_COLLECTION 51 --------------- 52 53 This is used to store the actual files. It begins with `count` entries: 54 ```c++ 55 struct FileEntry 56 { 57 char name[0x200]; // '\0' terminated 58 uint32_t field_200; 59 uint32_t data_offset; 60 uint32_t data_size; 61 uint32_t link_start; 62 uint32_t link_count; 63 uint32_t padding[7]; // always 0 64 }; 65 sizeof(FileEntry) == 0x230 66 ``` 67 68 `Section::data_size` includes both the size of these entries and the actual file 69 data size (it's `last_entry.offset + last_entry.size + pad`). 70 71 `name` is the name of the file. `field_200` is either 0 for all files, or they 72 contain the index of the file (?). The file contents start at `data_offset`, 73 (unlike other offsets) **relative to the beginning of FILE_COLLECTION**, and 74 it's `data_size` bytes long. `link_count` contains the number of links this file 75 has (see below), `link_start` is an index inside the `FILE_LINK`. 76 77 FILE_LINK 78 --------- 79 80 It contains `count` entries: 81 ```c++ 82 struct LinkEntry 83 { 84 uint32_t field_00; // always 0 85 uint32_t linked_file_id; 86 uint32_t link_id; 87 uint32_t padding[5]; // always 0 88 }; 89 sizeof(LinkEntry) == 0x20; 90 ``` 91 92 `Section::data_size` is `count*sizeof(LinkEntry)`. `linked_file_id` contains the 93 index of the link destination (inside `FILE_COLLECTION`). `link_id` counts the 94 index of the current file's link (it's an incrementing counter reset with every 95 new file). 96 97 In the original files, files and the corresponding link entries are in the same 98 order, if a file has 0 links, the `link_start` is still set to where it would 99 began if it'd actually have links. 100 101 Example 102 ------- 103 104 Probably the way I described this whole link thing is not clear enough, so 105 here's an example: 106 107 `FILE_COLLECTION` contains this: 108 ```c 109 [0] = { .name = "a.bin", .link_start = 0, .link_count = 2 }, 110 [1] = { .name = "b.bin", .link_start = 2, .link_count = 1 }, 111 [2] = { .name = "c.bin", .link_start = 3, .link_count = 0 }, 112 [3] = { .name = "d.bin", .link_start = 3, .link_count = 1 }, 113 ``` 114 115 And `FILE_LINK` contains this: 116 ```c 117 [0] = { .linked_file_id = 1, link_id = 0 }, 118 [1] = { .linked_file_id = 2, link_id = 1 }, 119 [2] = { .linked_file_id = 2, link_id = 0 }, 120 [3] = { .linked_file_id = 1, link_id = 0 }, 121 ``` 122 123 This means that `a.bin` has two links, starting at 0 in `FILE_LINK`. `link[0]` 124 says it's a link to `file[1]` (i.e. `b.bin`), and `link[1]` says it's a link to 125 `file[2]` (i.e. `c.bin`). 126 127 `b.bin` only has one link, at `link[2]`. It's a link to `file[2]` (i.e. 128 `c.bin`). 129 130 `c.bin` has zero links, but `link_start` still contains 3, because the links 131 would be there if there were one. Finally `d.bin` contains a single link, still 132 starting at 3, since `3+0=0`. 133 134 The actual link graph looks like this: 135 ``` 136 a.bin ---> b.bin <--- d.bin 137 | | 138 | v 139 +------> c.bin 140 ```