libxivdat/lib.rs
1// Copyright 2021 Carrie J Vrtis
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! A Rust library for working with Final Fantasy XIV .DAT files.
16//! These files store client-side game config including macros, hotkeys, and ui settings.
17//!
18//! Libxivdat provides low-level file i/o via [`DATFile`](crate::dat_file::DATFile),
19//! a [`std::fs::File`]-like interface that automatically manages the header, footer, and content
20//! masking of DAT files.
21//!
22//! Each DAT file contains unique data structures. Higher-level support for specific file types is
23//! implemented on a type-by-type basis as optional features. See the chart below
24//! for more information and feature names.
25//!
26//! # DAT Data Structures
27//!
28//! Internally, some DAT file content blocks use a variable-length data structure referred to as a [`section`](crate::section)
29//! in this library. A section consists of a single UTF-8 char type tag, u16le size, and a null-terminated
30//! UTF-8 string. A single resource (ie, a macro) is then comprised of a repeating pattern of sections.
31//! Other DAT files use fixed-size resource blocks, with each resource immediately following the last.
32//! These are referred to as "Block DATs" below.
33//!
34//! Some DAT files contain unique binary data that does not follow the "standard" DAT format. Others contain
35//! UTF-8 plaintext and are not binary files at all. Support for these files is not currently planned.
36//!
37//! ## DAT Support Table
38//!
39//! | Symbol | Description |
40//! |--------|-----------------|
41//! | ✅ | Full support |
42//! | 🌀 | Partial support |
43//! | ❌ | No support |
44//!
45//! | File | Contains | Type | DATFile Read/Write | High Level Module |
46//! |--------------------|----------------------------------|------------|--------------------|-------------------|
47//! | ACQ.DAT | Recent /tell history | Section | ✅ | 🌀 - `section` |
48//! | ADDON.DAT | ? | Unique | ❌ | ❌ |
49//! | COMMON.DAT | Character configuration | Plaintext | ❌ | ❌ |
50//! | CONTROL0.DAT | Gamepad control config | Plaintext | ❌ | ❌ |
51//! | CONTROL1.DAT | Keyboard/mouse control config | Plaintext | ❌ | ❌ |
52//! | FFXIV_CHARA_XX.DAT | Character appearance presets | Unique | ❌ | ❌ |
53//! | GEARSET.DAT | Gearsets | Block | ✅ | ❌ |
54//! | GS.DAT | Gold Saucer config (Triad decks) | Block | ✅ | ❌ |
55//! | HOTBAR.DAT | Hotbar layouts | Block | ✅ | ❌ |
56//! | ITEMFDR.DAT | "Search for item" indexing? | Block | ✅ | ❌ |
57//! | ITEMODR.DAT | Item order in bags | Block | ✅ | ❌ |
58//! | KEYBIND.DAT | Keybinds | Section | ✅ | 🌀 - `section` |
59//! | LOGFLTR.DAT | Chat log filters? | Block | ✅ | ❌ |
60//! | MACRO.DAT | Character-specific macros | Section | ✅ | ✅ - `macro` |
61//! | MACROSYS.DAT | System-wide macros | Section | ✅ | ✅ - `macro` |
62//! | UISAVE.DAT | UI config | Block | ✅ | ❌ |
63//!
64//! # Examples:
65//!
66//! ## Reading a file:
67//!
68//! ```rust
69//! use libxivdat::dat_file::read_content;
70//! # let path_to_dat_file = "./resources/TEST.DAT";
71//! let data_vec = read_content(&path_to_dat_file).unwrap();
72//! ```
73//!
74//! ## Writing to an existing file:
75//! DAT files contain metadata in the header that pertains to how data should be written.
76//! Because of this, creating a new DAT file and writing contents are separate steps.
77//!
78//! ```rust
79//! use libxivdat::dat_file::write_content;
80//! # use libxivdat::dat_file::DATFile;
81//! # use libxivdat::dat_type::DATType;
82//! # extern crate tempfile;
83//! # use tempfile::tempdir;
84//! # let temp_dir = tempdir().unwrap();
85//! # let path_to_dat_file = temp_dir.path().join("TEST.DAT");
86//! # DATFile::create(&path_to_dat_file, DATType::Macro).unwrap();
87//! let data_vec = write_content(&path_to_dat_file, b"This is some data.").unwrap();
88//! ```
89//!
90//! ## Creating a new file:
91//!
92//! ```rust
93//! use libxivdat::dat_file::DATFile;
94//! use libxivdat::dat_type::DATType;
95//! # extern crate tempfile;
96//! # use tempfile::tempdir;
97//! # let temp_dir = tempdir().unwrap();
98//! # let path_to_dat_file = temp_dir.path().join("TEST.DAT");
99//! DATFile::create_with_content(&path_to_dat_file, DATType::Macro, b"This is some data.").unwrap();
100//! ```
101//!
102//! ## File-like access:
103//!
104//! ```rust
105//! use libxivdat::dat_file::read_content;
106//! use libxivdat::dat_file::DATFile;
107//! use libxivdat::dat_type::DATType;
108//! use std::io::{Read,Seek,SeekFrom,Write};
109//! # extern crate tempfile;
110//! # use tempfile::tempdir;
111//! # let temp_dir = tempdir().unwrap();
112//! # let path_to_dat_file = temp_dir.path().join("TEST.DAT");
113//! # DATFile::create(&path_to_dat_file, DATType::Macro).unwrap();
114//!
115//! let mut dat_file = DATFile::open(&path_to_dat_file).unwrap();
116//!
117//! let mut first_256_bytes = [0u8; 256];
118//! dat_file.read(&mut first_256_bytes).unwrap();
119//! ```
120
121/// Contains the [`DATError`](crate::dat_error::DATError) wrapper error. This error type is used
122/// for all functions that do not implement a `std::io` trait.
123pub mod dat_error;
124/// Contains a generic, low-level tool set for working with any standard binary DAT files.
125/// This provides the convenience functions [`read_content()`](crate::dat_file::read_content)
126/// and [`write_content()`](crate::dat_file::write_content) as well as the [`std::fs::File`]-like
127/// [`DATFile`](crate::dat_file::DATFile) interface.
128pub mod dat_file;
129/// Contains the enum of all supported file types, [`DATType`](crate::dat_type::DATType) and
130/// functions for accessing default header and mask values specific to each type.
131pub mod dat_type;
132/// Contains general-purpose traits and functions applicable to all high-level, file-type-specific
133/// modules such as [`xiv_macro`].
134///
135/// Enabled by feature `high-level`, which is implied by any file type feature.
136#[cfg(feature = "high-level")]
137pub mod high_level;
138/// Contains a generic tool set for working with any section-based binary DAT files.
139/// This module contains two equivalent implementations: [`Section`](crate::section::Section),
140/// [`read_section()`](crate::section::read_section), and [`read_section_content()`](crate::section::read_section_content)
141/// for working with files on disk and [`SectionData`](`crate::section::SectionData),
142/// [`as_section()`](crate::section::as_section`), and [`as_section_vec()`](crate::section::as_section_vec)
143/// for working with pre-allocated byte arrays.
144///
145/// Because sections are variable-length data structures, no functions for writing sections in-place are
146/// provided. The recommended approach to writing section-based files is to read the entire file, then
147/// write an entirely new content block with [`write_content()`](crate::dat_file::write_content).
148pub mod section;
149/// Contains the high-level toolkit for working with macro files, `MACRO.DAT` and `MACROSYS.DAT`.
150/// This module contains two equivalent implementations: [`Macro`](crate::xiv_macro::Macro),
151/// [`read_macro()`](crate::xiv_macro::read_macro), and [`read_macro_content()`](crate::xiv_macro::read_macro_content)
152/// for working with files on disk and [`MacroData`](`crate::xiv_macro::MacroData),
153/// [`as_macro()`](crate::xiv_macro::as_macro`), and [`as_macro_vec()`](crate::xiv_macro::as_macro_vec)
154/// for working with pre-allocated byte arrays and [`SectionData](crate::section::SectionData).
155///
156/// Enabled by feature `macro`.
157///
158/// # Examples
159///
160/// ## Reading a macro file
161/// ```rust
162/// use libxivdat::xiv_macro::read_macro_content;
163/// use libxivdat::xiv_macro::icon::MacroIcon;
164///
165/// let macro_contents = read_macro_content("./resources/TEST_MACRO.DAT").unwrap();
166///
167/// assert_eq!(macro_contents[0].title, "0");
168/// assert_eq!(macro_contents[0].lines[0], "DefaultIcon");
169/// assert_eq!(macro_contents[0].get_icon().unwrap(), MacroIcon::DefaultIcon);
170///
171/// assert_eq!(macro_contents[1].title, "1");
172/// assert_eq!(macro_contents[1].lines[0], "DPS1");
173/// assert_eq!(macro_contents[1].get_icon().unwrap(), MacroIcon::DPS1);
174/// ```
175///
176/// ## Writing a macro file
177/// Macro files use variable-length [`Sections`](crate::section::Section) to store data on disk,
178/// so it is not possible to easily overwrite a single macro in-place. The recommended approach to modifying
179/// macros is to read and write the entire file as a block.
180/// ```rust
181/// use libxivdat::dat_file::write_content;
182/// use libxivdat::xiv_macro::{read_macro_content, to_writeable_bytes, Macro};
183/// use libxivdat::xiv_macro::icon::MacroIcon;
184/// # use libxivdat::dat_file::DATFile;
185/// # use libxivdat::dat_type::DATType;
186///
187/// # extern crate tempfile;
188/// # use tempfile::tempdir;
189/// # let temp_dir = tempdir().unwrap();
190/// # let out_path = temp_dir.path().join("TEST.DAT");
191/// # DATFile::create(&out_path, DATType::Macro).unwrap();
192///
193/// let mut macro_vec = read_macro_content("./resources/TEST_MACRO.DAT").unwrap();
194/// // Replace macro #0 with a new macro. Macro::new will enforce the game's specs for macros.
195/// macro_vec[0] = Macro::new(
196/// String::from("libxivdat was here"),
197/// vec![String::from("/sh I <3 libxivdat!!!")],
198/// MacroIcon::SymbolExclamation
199/// ).unwrap();
200///
201/// // Write it back out to a file. to_writeable_bytes will validate every macro in the vector.
202/// let out_bytes = to_writeable_bytes(¯o_vec).unwrap();
203/// write_content(&out_path, &out_bytes);
204/// ```
205#[cfg(feature = "macro")]
206pub mod xiv_macro {
207 pub use crate::high_level_modules::r#macro::*;
208}
209/// High-level, file-type-specific submodules container.
210mod high_level_modules;