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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
//! # Binary BLK
//! This module describes the binary BLK format and all of its know features and flags.
//! > ⚠ **Warning: Unless stated otherwise, all integers are Little-endian**
//!
//! ## Terminology
//! For ease of writing and reading, there are a few terms i will establish for this chapter
//! - u32 -> 32-bit unsigned integer
//! - u64 -> 64-bit unsigned integer
//! - f32 -> 32 bit float
//! - f64 -> 64 bit float
//! - \[T; N\] -> N long array of T
//! - offset -> absolute offset from 0 in the file
//! - nm -> A file containing Strings that is not in the BLK binary itself
//! - dict -> A ZSTD dictionary used in batch compressing many BLK files
//! - ULEB -> Unsigned LEB encoded variable length integer format: `https://en.wikipedia.org/wiki/LEB128`
//! - Name/Name map -> String as key or value in the BLK, map is an array of Strings
//!
//! ### Types
//! BLK has 12 data-types, 6 of which are unique, the rest being arrays of said types.
//!
//! |Name|Byte identifier|Layout|Size in bytes|[Inline](#inlining)|
//! |-|-|-|-|-|
//! |String|0x01|Zero terminated string|Variable||
//! |Int|0x02|i32|4|yes|
//! |Float|0x03|f32|4|yes|
//! |Float2|0x04|\[f32; 2\]|8||
//! |Float3|0x05|\[f32; 3\]|12||
//! |Float4|0x06|\[f32; 4\]|16||
//! |Int2|0x07|\[i32; 2\]|8||
//! |Int3|0x08|\[i32; 3\]|12||
//! |Bool|0x09|boolean|4|yes|
//! |Color|0x0a|\[u8; 4\]|4|yes|
//! |Float12|0x0b|\[f32; 12\]|48||
//! |Long|0x0c|i64|8||
//!
//! ### Inlining
//! When a type is inline, it means that its offset field contains the types data (used for small types 32 bits or smaller).
//! Otherwise, the type data is an offset where the actual payload can be found.
//!
//! ### Kinds of BLK files
//! There is not just one type of BLK, there are some important differences to denote.
//! |Byte ID|String ID|Description|
//! |-|-|-|
//! |0x00|BBF|A legacy format that this library does not understand|
//! |0x01|FAT|A standalone BLK binary, about as normal as it gets|
//! |0x02|FAT_ZST|Same as FAT, but ZSTD compressed|
//! |0x03|SLIM|A BLK like FAT, but with all strings outlined to the nm|
//! |0x04|SLIM_ZST|Same as SLIM, but ZSTD compressed|
//! |0x05|SLIM_ZSTD_DICT|Same as SLIM, but ZSTD compressed using the dict|
//!
//! ### Name reference
//! Whenever a String is used in the name-map or field-map, this layout applies.
//! If the tag-bit is set, it means the index has to be looked up from the [external nm](#external-nm), otherwise the regular [nm](#name-map),
//! |Tag|Index|
//! |-|-|
//! |1 bit| 31 bit unsigned integer|
//!
//! ## File layout
//! Now that we understand all necessary terms and types for BLK, were almost ready to encode/decode them.
//! I will first explain the layout of a regular FAT file, then elaborate on the differences to the other kinds.
//! 
//! The file starts off with a single byte describing its [kind](#kinds-of-blk-files), FAT in this case, of course.
//! After that, we begin the first section of data already called the [Name map].
//!
//! ### Name Map
//! Defines where any Strings used as keys or values in this BLK.
//! In the case of SLIM, only the names count ULEB will be present, skipping straight to the [struct count](#struct-count).
//! In the case of FAT, following the names count (ULEB) N is the names buffer size (ULEB) S.
//! After this comes all null seperated strings that should be as many as N specified.
//!
//! ### Block count
//! A single ULEB defining how many nested structs the BLK file contains (used later).
//!
//! ### Field map
//! Similar to the name map, here we first get the amount of fields followed by the size of the payload buffer.
//! The field payloads come before the field definitions and therefore need to be used during the decoding of the fields.
//! Each field definition is 32 bits in size structured as such:
//! |[Name ID](#name-reference)|Type ID|Offset|
//! |-|-|-|
//! |u24|u8|u32|
//! ---
//! When the type is inline, simply interpret the offset as its payload.
//! Otherwise, use the offset relative to the start of the payload buffer, reading as many bytes as the type needs.
//!
//! ### Nesting map
//! Until now, we have only read and parsed a list of fields. But you may ask, doesn't BLK support nested structs?
//! Indeed, it does, and it uses the following layout to figure out which fields and struct correspond to which parent struct.
//! The data layout is as such:
//! |Index|Struct name|field count|sub-structs count|sub-struct index (optional)|
//! |-|-|-|-|
//! |ULEB|[Name ID](#name-reference)|ULEB|ULEB|
//! ---
//! Explaining the algorithm necessary to structure this data is not trivial, so I will explain each value and its purpose with care.
//! However, I believe that, reading [`crate::blk::blk_block_hierarchy::FlatBlock`] (implementation) together with this text will work better than just the text.
//!
//! To start off, we first get the index, which uniquely identifies any struct, where 0 is the root/core struct.
//! Together with the index, we can determine the name, which is a [Name ID](#name-reference) or undefined and irrelevant if the index is 0.
//!
//! Field `count` defines how many fields from [the field map](#field-map) belong to this struct in the order as they appear.
//! Keeping track of the sum of previous`count`'s is important as current `count` starts from where the last field ended.
//!
//! Sub-structs count defines how many substructs there are.
//!
//! Sub-structs index defines which other struct are contained in this one, using the same indexing system as field count.
//! **This value is not present when sub-structs count was 0.**
//!
//! This mechanism is best explained with an example to go with it:
//! Lets use this BLK as our working minimal example:
//! ```blk
//! "vec4f":p4 = 1.25, 2.5, 5, 10
//! "int":i = 42
//! "long":i64 = 0x40
//! "alpha" {
//! "str":t = "hello"
//! "bool":b = true
//! "color":c = 0x1, 0x2, 0x3, 0x4
//! "gamma" {
//! "vec2i":ip2 = 3, 4
//! "vec2f":p2 = 1.25, 2.5
//! "transform":m = [[1, 0, 0] [0, 1, 0] [0, 0, 1] [1.25, 2.5, 5]]
//! }
//! }
//! "beta" {
//! "float":r = 1.25
//! "vec2i":ip2 = 1, 2
//! "vec3f":p3 = 1.25, 2.5, 5
//! }
//! ```
//! The Nesting map would look like the following:
//! |Index|Name|Indexes|Sub-blocks|Binary representation|
//! |-|-|-|-|-|
//! |0|N.A.|0,1,2|1,2|`0x00 0x03 0x02 0x01`|
//! |1|alpha|3,4,5|3|`0x04 0x03 0x01 0x03` |
//! |2|beta|6,7,8||`0x0C 0x03 0x00` |
//! |3|gamma|9,10,11||`0x08 0x03 0x00` |
use ;
pub use DecoderDictionary;
use blk_str;
use cfg_if;
use Report;
use crate;
/// Decodes flat map of fields into the corresponding nested datastructures
pub
/// Defines the recursive/nested structure that BLK files are represented with internally
/// Defines the primitive types that BLK stores
/// Shared error that is returned from hot functions,
/// otherwise, [`color_eyre::Report`] is used
/// One-byte file header that each blk file begins with
/// Utility function to decode ULEB128 encoded files
/// <https://en.wikipedia.org/wiki/LEB128>
/// Struct storing a shared map of strings that multiple BLK files reference
cfg_if!
/// Collection of macros and functions used in all BLK modules
/// Zstandard unpacking functionality
/// Implementations for serializing into human readable text formats from internal representation
/// Implementations for deserializing into internal representation format from text
/// Implementation for deserializing internal representation to binary form
/// Highest-level function for unpacking one BLK explicitly, for direct low level control call [`binary_deserialize::parser::parse_blk`]