implement FString for ANSI and WCS2 (UTF-16 1251) encodings

This commit is contained in:
mykola2312 2023-08-29 07:10:52 +03:00
parent 1b05779355
commit 650cbcaaca
5 changed files with 90 additions and 1 deletions

16
Cargo.lock generated
View file

@ -20,6 +20,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "deflate"
version = "1.0.0"
@ -29,6 +35,15 @@ dependencies = [
"adler32",
]
[[package]]
name = "encoding_rs"
version = "0.8.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
dependencies = [
"cfg-if",
]
[[package]]
name = "fot-save-edit"
version = "0.1.0"
@ -36,6 +51,7 @@ dependencies = [
"anyhow",
"byteorder",
"deflate",
"encoding_rs",
"inflate",
"memmem",
]

View file

@ -9,5 +9,6 @@ edition = "2021"
anyhow = "1.0.75"
byteorder = "1.4.3"
deflate = "1.0.0"
encoding_rs = "0.8.33"
inflate = "0.4.5"
memmem = "0.1.1"

63
src/fot/fstring.rs Normal file
View file

@ -0,0 +1,63 @@
use super::decoder::Decoder;
use super::raw::Raw;
use anyhow::Result;
use std::io::Cursor;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use encoding_rs::WINDOWS_1251;
use std::str;
// FString - Fallout String
#[derive(Debug, PartialEq)]
pub enum FStringEncoding {
ANSI,
WCS2
}
#[derive(Debug)]
pub struct FString {
encoding: FStringEncoding,
str: String
}
impl Decoder for FString {
fn decode(raw: &Raw, offset: usize, _: usize) -> Result<Self> {
let mut rdr = Cursor::new(&raw.mem[offset..]);
let flen = rdr.read_u32::<LittleEndian>()? as usize;
let len = flen ^ (1<<31);
let start = offset + 4;
if flen & (1<<31) == 0 { // ANSI
let str = str::from_utf8(&raw.mem[start..start+len])?;
Ok(FString { encoding: FStringEncoding::ANSI, str: str.to_string() })
} else { // WCS2
let chars: Vec<u8> = raw.mem[start..start+len*2]
.iter().step_by(2).copied().collect();
let (str, _, _) = WINDOWS_1251.decode(&chars);
Ok(FString { encoding: FStringEncoding::WCS2, str: str.to_string() })
}
}
fn encode(&self) -> Raw {
let mut buf = vec![0u8, 4];
let mut wdr = Cursor::new(&mut buf[..]);
if self.encoding == FStringEncoding::ANSI {
let _ = wdr.write_u32::<LittleEndian>(self.str.len() as u32 ^ (1<<31));
buf.append(&mut self.str.clone().into_bytes());
} else { // WCS2
let _ = wdr.write_u32::<LittleEndian>(self.str.len() as u32 | (1<<31));
let (chars, _, _) = WINDOWS_1251.encode(self.str.as_str());
for &c in chars.iter() {
buf.push(c);
buf.push(0);
}
};
Raw { offset: 0, size: buf.len(), mem: buf }
}
fn get_enc_size(&self) -> usize {
match self.encoding {
FStringEncoding::ANSI => 4 + self.str.len(),
FStringEncoding::WCS2 => 4 + self.str.len() * 2
}
}
}

View file

@ -1,6 +1,7 @@
use super::decoder::Decoder;
use super::raw::Raw;
use super::tag::Tag;
use super::fstring::FString;
use anyhow::anyhow;
use anyhow::Result;
use std::io::Cursor;
@ -19,6 +20,13 @@ pub struct World {
impl World {
const WORLD_TAG_LEN: usize = 11;
const WORLD_HDR_LEN: usize = 0x13;
pub fn test(&self) -> Result<()> {
let a = FString::decode(&self.data, 0xF6, 0)?;
dbg!(&a);
Ok(())
}
}
impl Decoder for World {

View file

@ -14,5 +14,6 @@ fn main() {
let save = Save::load(Path::new(save_path)).expect("load save");
save.save(Path::new("out.sav")).expect("failed to save");
save.world.test().expect("test");
//save.save(Path::new("out.sav")).expect("failed to save");
}