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
//! # bdat-rs
//!
//! BDAT is a proprietary binary file format used by [MONOLITHSOFT] for their Xenoblade Chronicles
//! games. It is a tabular data format (like CSV, TSV, etc.) with named tables and typed fields.
//! In newer versions of the format, files and tables (also called sheets) can be memory-mapped
//! for use in programs based on the C memory model.
//!
//! This crate allows reading and writing BDAT tables and files.
//!
//! ## Reading BDAT tables
//!
//! ### Reading Xenoblade 3 ("modern") tables
//!
//! The crate exposes the [`from_bytes`] and [`from_reader`] functions in the [`modern`] module
//! to parse Xenoblade 3 BDAT files from a slice or a [`std::io::Read`] stream respectively.
//!
//! The [`label_hash!`] macro can be used to quickly generate hashed labels from plain-text strings.
//!
//! See also: [`ModernTable`]
//!
//! ```
//! use bdat::{BdatResult, SwitchEndian, BdatFile, modern::ModernTable, label_hash};
//! use bdat::hash::murmur3_str;
//!
//! fn read_xc3() -> BdatResult<()> {
//! let data = [0u8; 0];
//! // also bdat::from_reader for io::Read implementations.
//! let mut bdat_file = bdat::modern::from_bytes::<SwitchEndian>(&data)?;
//!
//! let table: &ModernTable = &bdat_file.get_tables()?[0];
//! if table.name() == &label_hash!("CHR_PC") {
//! // Found the character table, get Noah's HP at level 99
//! let noah = table.row(1);
//! // Alternatively
//! let noah = table.row_by_hash(murmur3_str("PC_NOAH"));
//!
//! let noah_hp = noah
//! .get(label_hash!("HpMaxLv99"))
//! .get_as::<u32>();
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! ### Reading tables from other games ("legacy")
//!
//! Similarly, the [`legacy`] module contains functions to read and write legacy tables.
//!
//! There are differences between games that use the legacy format, so specifying a
//! [`BdatVersion`] is required.
//! If you don't know the legacy sub-version, you can use [`detect_file_version`] or
//! [`detect_bytes_version`].
//!
//! See also: [`LegacyTable`]
//!
//! ```
//! use bdat::{BdatResult, SwitchEndian, BdatFile, legacy::LegacyTable, LegacyVersion, Label};
//!
//! fn read_legacy() -> BdatResult<()> {
//! // Mutable access is required as text might need to be unscrambled.
//! let mut data = [0u8; 0];
//! // Use `WiiEndian` for Xenoblade (Wii) and Xenoblade X.
//! let mut bdat_file = bdat::legacy::from_bytes::<SwitchEndian>(
//! &mut data,
//! LegacyVersion::Switch
//! )?;
//!
//! let table: &LegacyTable = &bdat_file.get_tables()?[0];
//! if table.name() == "CHR_Dr" {
//! // Found the character table, get Rex's HP at level 99
//! let rex = table.row(1);
//! // We need to distinguish between legacy cell types
//! let rex_hp = rex.get("HpMaxLv99")
//! .as_single()
//! .unwrap()
//! .get_as::<u32>();
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! ### Version auto-detect
//!
//! If the table format isn't known, [`from_bytes`] and [`from_reader`] from the
//! crate root can be used instead.
//!
//! ```
//! use bdat::{BdatResult, SwitchEndian, BdatFile, compat::CompatTable, Label, label_hash};
//!
//! fn read_detect() -> BdatResult<()> {
//! // Mutable access is required, as this might be a legacy table.
//! let mut data = [0u8; 0];
//! // Endianness is also detected automatically.
//! let mut bdat_file = bdat::from_bytes(&mut data)?;
//!
//! // Can no longer assume the format.
//! let table: &CompatTable = &bdat_file.get_tables()?[0];
//! if table.name() == label_hash!("CHR_PC") {
//! // Found the character table, get Noah's HP at level 99.
//! // No hash lookup for rows!
//! let noah = table.row(1);
//! // We can't use the ergonomic functions from `ModernTable` here,
//! // so we need to handle the legacy cases, even if they don't
//! // concern modern tables.
//! let noah_hp = noah.get(label_hash!("HpMaxLv99"))
//! .as_single()
//! .unwrap()
//! .get_as::<u32>();
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! ## Writing BDAT tables
//! The `to_vec` and `to_writer` functions (in [`legacy`] and [`modern`]) can be used to write BDAT
//! files to a vector or a [`std::io::Write`] implementation.
//!
//! Writing fully requires the user to specify the BDAT version to use, by choosing the
//! appropriate module implementation.
//!
//! Tables obtained with the auto-detecting functions must be extracted or converted first.
//!
//! ```
//! use bdat::{BdatResult, LegacyVersion, SwitchEndian, WiiEndian};
//! use bdat::modern::ModernTable;
//! use bdat::legacy::LegacyTable;
//!
//! fn write_modern(table: &ModernTable) -> BdatResult<()> {
//! // also bdat::to_writer for io::Write implementations
//! let _written: Vec<u8> = bdat::modern::to_vec::<SwitchEndian>([table])?;
//! Ok(())
//! }
//!
//! fn write_legacy(table: &LegacyTable) -> BdatResult<()> {
//! // Endianness and version may vary, here it's writing Xenoblade X tables.
//! let _written: Vec<u8> = bdat::legacy::to_vec::<WiiEndian>([table], LegacyVersion::X)?;
//! Ok(())
//! }
//! ```
//!
//! ## Serde support
//! When the `serde` feature flag is enabled, this crate's types will implement `Serialize` and
//! `Deserialize`.
//!
//! While the crate doesn't support serializing/deserializing BDAT to Rust types, this can be used
//! to transcode BDAT to other formats.
//! The [bdat-toolset] crate will convert BDAT to CSV and JSON, and JSON to BDAT.
//!
//! [MONOLITHSOFT]: https://www.monolithsoft.co.jp/
//! [bdat-toolset]: https://github.com/RoccoDev/bdat-rs/tree/master/toolset
//! [`LegacyTable`]: crate::legacy::LegacyTable
//! [`ModernTable`]: crate::modern::ModernTable
pub
pub
pub
pub use BdatError;
pub use Result as BdatResult;
pub use *;
pub use ;
pub use ;
pub use Label;
pub use *;
pub use *;
pub use compat;
pub use *;