rpfm_lib/lib.rs
1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11//! Core library for reading and writing Total War game files.
12//!
13//! This crate provides comprehensive support for reading, writing, and manipulating file formats
14//! used by Creative Assembly in Total War games since Empire: Total War. It forms the foundation
15//! of the Rusted PackFile Manager (RPFM) project.
16//!
17//! # Supported Games
18//!
19//! - Total War: Shogun 2 Complete Edition
20//! - Total War: Pharaoh - Dynasties
21//! - Total War: Pharaoh
22//! - Total War: Warhammer 3
23//! - Total War Saga: Troy
24//! - Total War: Three Kingdoms
25//! - Total War: Warhammer 2
26//! - Total War: Warhammer
27//! - Total War Saga: Thrones of Britannia
28//! - Total War: Attila
29//! - Total War: Rome 2
30//! - Total War: Shogun 2
31//! - Total War: Napoleon
32//! - Total War: Empire
33//!
34//! # Supported File Formats
35//!
36//! The library supports 30+ file types including:
37//!
38//! - **Pack Files** (`.pack`): Container format for all game assets
39//! - **Database Tables** (`db/`): Game data with versioned schemas
40//! - **Localisation Files** (`.loc`): Translated text strings
41//! - **3D Models** (`.rigid_model_v2`): Unit and building meshes
42//! - **Animations**: AnimPack, AnimFragment, AnimsTable, MatchedCombat
43//! - **Audio**: Sound banks (`.bnk`), sound events, DAT containers
44//! - **Images**: DDS textures, atlases
45//! - **Maps**: BMD (battle map data), tile databases, vegetation
46//! - **Campaign**: ESF (save files), startpos
47//! - **UI**: UIC components, portrait settings, fonts
48//! - **Scripts**: Lua, XML, and other text formats
49//!
50//! See the [`files`] module for detailed information on each file type and its support level.
51//!
52//! # Architecture
53//!
54//! The library is organized into several key modules:
55//!
56//! - [`files`]: File format parsers and writers (30+ types)
57//! - [`schema`]: Database table schema definitions and versioning
58//! - [`binary`]: Low-level binary I/O utilities
59//! - [`games`]: Game-specific configuration and version detection
60//! - [`compression`]: LZ4, ZStd, and LZMA compression support
61//! - [`encryption`]: Pack file encryption/decryption
62//! - [`error`]: Error types and result handling
63//! - [`integrations`]: Optional Assembly Kit, Git and GitHub integration
64//!
65//! # Feature Flags
66//!
67//! - `integration_assembly_kit`: Enable Assembly Kit raw table parsing
68//! - `integration_git`: Enable Git repository operations
69//!
70//! # Examples
71//!
72//! ## Reading a Pack File
73//!
74//! ```ignore
75//! use rpfm_lib::files::pack::Pack;
76//! use rpfm_lib::games::supported_games::{SupportedGames, KEY_WARHAMMER_3};
77//! use std::path::PathBuf;
78//!
79//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
80//! let path = PathBuf::from("path/to/pack.pack");
81//! let games = SupportedGames::default();
82//! let game_info = games.game(&KEY_WARHAMMER_3).unwrap();
83//! let pack = Pack::read_and_merge(&[path], game_info, true, false, false)?;
84//!
85//! for file in pack.files().values() {
86//! println!("{}", file.path_in_container_raw());
87//! }
88//! # Ok(())
89//! # }
90//! ```
91//!
92//! ## Working with Database Tables
93//!
94//! ```ignore
95//! use rpfm_lib::files::{db::DB, Decodeable, DecodeableExtraData, RFile, RFileDecoded};
96//! use rpfm_lib::schema::Schema;
97//! use std::path::Path;
98//!
99//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
100//! let schema_path = Path::new("path/to/schema.ron");
101//! let schema = Schema::load(&schema_path, None)?;
102//! let mut extra_data = DecodeableExtraData::default();
103//! extra_data.set_schema(Some(&schema));
104//!
105//! // Decode a DB file (assuming pack is loaded)
106//! // let mut file = pack.files_by_path(&path, false).first().unwrap();
107//! // file.decode(&Some(extra_data), false, true)?;
108//! //
109//! // if let Ok(RFileDecoded::DB(db)) = file.decoded() {
110//! // println!("Table {} has {} rows", db.table_name(), db.data().len());
111//! // }
112//! # Ok(())
113//! # }
114//! ```
115//!
116//! # Related Crates
117//!
118//! - `rpfm_extensions`: Higher-level features (dependencies, diagnostics, search, optimizer)
119//! - `rpfm_ui`: Qt-based desktop application
120
121use regex::Regex;
122
123use std::sync::LazyLock;
124
125pub mod binary;
126pub mod compression;
127pub mod encryption;
128pub mod error;
129pub mod files;
130pub mod games;
131pub mod integrations;
132pub mod notes;
133pub mod schema;
134pub mod utils;
135mod xml;
136
137#[cfg(test)] mod utils_test;
138
139/// Regular expression to identify database table file paths.
140///
141/// Matches paths in the format: `db/{table_name}_tables/{file}`
142///
143/// # Examples
144///
145/// - `db/units_tables/core_units.bin` → matches
146/// - `db/buildings_tables/data.bin` → matches
147/// - `data/units.txt` → does not match
148pub static REGEX_DB: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"db/[^/]+_tables/[^/]+$").unwrap());
149
150/// Regular expression to identify CEO database table file paths. These do not use the normal db prefix
151/// due to crashes when loading them in mods ingame.
152///
153/// Matches paths in the format: `ceo_db/{table_name}_tables/{file}`
154///
155/// # Examples
156///
157/// - `ceo_db/units_tables/core_units.bin` → matches
158/// - `ceo_db/buildings_tables/data.bin` → matches
159/// - `data/units.txt` → does not match
160pub static REGEX_CEO_DB: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"ceo_db/[^/]+_tables/[^/]+$").unwrap());
161
162/// Regular expression to identify portrait settings file paths.
163///
164/// Matches any path ending with `portrait_settings` followed by optional characters and `.bin`.
165///
166/// # Examples
167///
168/// - `portraits/portrait_settings.bin` → matches
169/// - `data/portrait_settings_v2.bin` → matches
170/// - `other/settings.bin` → does not match
171pub static REGEX_PORTRAIT_SETTINGS: LazyLock<Regex> = LazyLock::new(|| Regex::new(r".*portrait_settings\S*\.bin$").unwrap());