Skip to main content

rpfm_lib/binary/
mod.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//! This module contains the traits [`ReadBytes`] and [`WriteBytes`], used to read binary data
12//! into known types and write them back to binary.
13//!
14//! These traits are automatically implemented for anything that implements [`Read`] + [`Seek`]
15//! (for [`ReadBytes`]) or [`Write`] (for [`WriteBytes`]).
16//!
17//! # Examples
18//!
19//! To read data using the [`ReadBytes`] trait, we can do this:
20//!
21//! ```rust
22//! use std::io::Cursor;
23//!
24//! use rpfm_lib::binary::ReadBytes;
25//!
26//! let data = vec![10, 0, 87, 97, 104, 97, 104, 97, 104, 97, 104, 97];
27//! let mut cursor = Cursor::new(data);
28//! let string = ReadBytes::read_sized_string_u8(&mut cursor).unwrap();
29//! println!("{}", string);
30//! ```
31//!
32//! And for writing data using the [`WriteBytes`] trait, we can do this:
33//!
34//! ```rust
35//! use rpfm_lib::binary::WriteBytes;
36//!
37//! let mut data = vec![];
38//! data.write_string_u8("Wahahahaha").unwrap();
39//! println!("{:?}", data);
40//! ```
41//!
42//! Check each trait docs for more info about all the types that can be read/written.
43//!
44//! # Simple types
45//!
46//! The most simple and common readable/writable types (always using LittleEndian) are:
47//!
48//! | Type            | Bytes                         | Binary Format                                   | Example | Explanation |
49//! | --------------- | ----------------------------- | ----------------------------------------------- | ------- | ----------- |
50//! | **[`bool`]**    | 1                             | ```00 or 01```                                  | 0/1     | Boolean value, 0 is false, 1 is true. Read with [`ReadBytes::read_bool`], write with [`WriteBytes::write_bool`]. |
51//! | **[`u8`]**      | 1                             | ```05```                                        | 5       | Unsigned Integer. Read with [`ReadBytes::read_u8`], write with [`WriteBytes::write_u8`]. |
52//! | **[`u16`]**     | 2                             | ```05 00```                                     | 5       | Unsigned Integer. Read with [`ReadBytes::read_u16`], write with [`WriteBytes::write_u16`]. |
53//! | **u24**         | 3                             | ```05 00 00```                                  | 5       | Unsigned Integer. Read with [`ReadBytes::read_u24`], write with [`WriteBytes::write_u24`]. |
54//! | **[`u32`]**     | 4                             | ```05 00 00 00```                               | 5       | Unsigned Integer. Read with [`ReadBytes::read_u32`], write with [`WriteBytes::write_u32`]. |
55//! | **[`u64`]**     | 8                             | ```05 00 00 00 00 00 00 00```                   | 5       | Unsigned Integer. Read with [`ReadBytes::read_u64`], write with [`WriteBytes::write_u64`]. |
56//! | **[`i8`]**      | 1                             | ```05```                                        | 5       | Signed Integer. Read with [`ReadBytes::read_i8`], write with [`WriteBytes::write_i8`]. |
57//! | **[`i16`]**     | 2                             | ```05 00```                                     | 5       | Signed Integer. Read with [`ReadBytes::read_i16`], write with [`WriteBytes::write_i16`]. |
58//! | **i24**         | 3                             | ```05 00 00```                                  | 5       | Signed Integer. Read with [`ReadBytes::read_i24`], write with [`WriteBytes::write_i24`]. |
59//! | **[`i32`]**     | 4                             | ```05 00 00 00```                               | 5       | Signed Integer. Read with [`ReadBytes::read_i32`], write with [`WriteBytes::write_i32`]. |
60//! | **[`i64`]**     | 8                             | ```05 00 00 00 00 00 00 00```                   | 5       | Signed Integer. Read with [`ReadBytes::read_i64`], write with [`WriteBytes::write_i64`]. |
61//! | **[`f32`]**     | 4                             | ```00 00 80 3F```                               | 1.0     | Floating Point Value. Read with [`ReadBytes::read_f32`], write with [`WriteBytes::write_f32`]. |
62//! | **[`f64`]**     | 8                             | ```00 00 00 00 00 00 F0 3F```                   | 1.0     | Floating Point Value. Read with [`ReadBytes::read_f64`], write with [`WriteBytes::write_f64`]. |
63//! | **StringU8**    | 2 (Length, u16) + Length.     | ```06 00 48 65 6C 6C 6F 77```                   | Hellow  | String encoded in UTF-8, with the first two bytes being the length of the String, in bytes. Read with [`ReadBytes::read_sized_string_u8`], write with [`WriteBytes::write_sized_string_u8`]. |
64//! | **StringU16**   | 2 (Length, u16) + Length * 2. | ```06 00 48 00 65 00 6C 00 6C 00 6F 00 77 00``` | Hellow  | String encoded in UTF-16, with the first two bytes being the length of the String, in characters. Read with [`ReadBytes::read_sized_string_u16`], write with [`WriteBytes::write_sized_string_u16`]. |
65//!
66//! # Complex types
67//!
68//! Apart of these, there are a few more complex types supported:
69//!
70//! | Type                      | Bytes                                     | Binary Format                                         | Example             | Explanation |
71//! | ------------------------- | ----------------------------------------- | ----------------------------------------------------- | ------------------- | ----------- |
72//! | **Optional i16**          | 3                                         | ```01 05 00```                                        | 5                   | Signed Integer with a boolean before. If the boolean is false, the value following it is always 0. Read with [`ReadBytes::read_optional_i16`], write with [`WriteBytes::write_optional_i16`]. |
73//! | **Optional i32**          | 5                                         | ```01 05 00 00 00```                                  | 5                   | Signed Integer with a boolean before. If the boolean is false, the value following it is always 0. Read with [`ReadBytes::read_optional_i32`], write with [`WriteBytes::write_optional_i32`]. |
74//! | **Optional i64**          | 9                                         | ```01 05 00 00 00 00 00 00 00```                      | 5                   | Signed Integer with a boolean before. If the boolean is false, the value following it is always 0. Read with [`ReadBytes::read_optional_i64`], write with [`WriteBytes::write_optional_i64`]. |
75//! | **OptionalStringU8**      | 1 (bool) + 2 (Length, u16) + Length.      | ```01 06 00 48 65 6C 6C 6F 77```                      | Hellow              | A StringU8 with a boolean before. If the boolean is false, there's no string after it. Read with [`ReadBytes::read_optional_string_u8`], write with [`WriteBytes::write_optional_string_u8`]. |
76//! | **OptionalStringU16**     | 1 (bool) + 2 (Length, u16) + Length.      | ```01 06 00 48 00 65 00 6C 00 6C 00 6F 00 77 00```    | Hellow              | A StringU16 with a boolean before. If the boolean is false, there's no string after it. Read with [`ReadBytes::read_optional_string_u16`], write with [`WriteBytes::write_optional_string_u16`]. |
77//! | **StringU8 0-Terminated** | Variable length, until there's a 00 byte. | ```48 65 6C 6C 6F 77 00```                            | Hellow              | A StringU8 without a size before it. The string just continues until a 00 byte is found. Read with [`ReadBytes::read_string_u8_0terminated`], write with [`WriteBytes::write_string_u8_0terminated`]. |
78//! | **StringU8 0-Padded**     | Fixed length, depends on the string.      | ```48 65 6C 6C 6F 77 00 00```                         | Hellow (max size 8) | A StringU8 without a size before it. Once the string ends, it continues with 00 until it reaches a specific length (usually X*2). Read with [`ReadBytes::read_string_u8_0padded`], write with [`WriteBytes::write_string_u8_0padded`]. |
79//! | **StringU16 0-Padded**    | Fixed length, depends on the string.      | ```48 00 65 00 6C 00 6C 00 6F 00 77 00 00 00 00 00``` | Hellow (max size 8) | Same as the StringU8 0-Padded, but each character is 2 bytes. Once the string ends, it continues with 00 00 until it reaches a specific length (usually X*2). Read with [`ReadBytes::read_string_u16_0padded`], write with [`WriteBytes::write_string_u16_0padded`]. |
80//! | **RGB**                   | 4                                         | ```33 44 55 00```                                     | #554433             | RGB Colour, written as Hex Values with the format BBGGRR00. Read with [`ReadBytes::read_string_colour_rgb`], write with [`WriteBytes::write_string_colour_rgb`]. |
81//!
82//! There are some even more complex types used by specific files, like ISO-8859-1 Strings or Number Packs.
83//! Those are explained in their respective file's documentation.
84//!
85//! [`ReadBytes`]: reader::ReadBytes
86//! [`WriteBytes`]: writer::WriteBytes
87//! [`Cursor`]: std::io::Cursor
88//! [`Read`]: std::io::Read
89//! [`Seek`]: std::io::Seek
90//! [`Write`]: std::io::Write
91//! [`File`]: std::fs::File
92
93mod reader;
94mod writer;
95
96pub use self::reader::ReadBytes;
97pub use self::writer::WriteBytes;
98
99#[cfg(test)] mod reader_test;
100#[cfg(test)] mod writer_test;