use crate::prelude::*;
use crate::util::assert;
use crate::wad::chunk::ChunkName;
use crate::wad::deserialize::reader::DataReader;
use crate::wad::elements::GMChunk;
use crate::wad::elements::GMElement;
use crate::wad::serialize::builder::DataBuilder;
const ALIGNMENT: u32 = 4;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct GMStrings;
impl GMChunk for GMStrings {
const NAME: ChunkName = ChunkName::new("STRG");
fn exists(&self) -> bool {
true
}
}
impl GMElement for GMStrings {
fn deserialize(reader: &mut DataReader) -> Result<Self> {
let pointers: Vec<u32> = reader.read_simple_list()?;
let is_aligned: bool = pointers.iter().all(|&p| p.is_multiple_of(ALIGNMENT));
let mut strings: Vec<String> = Vec::with_capacity(pointers.len());
for pointer in pointers {
if is_aligned {
reader.align(ALIGNMENT)?;
}
reader.assert_pos(pointer, "String")?;
let string_length = reader.read_u32()?;
let string: String = reader.read_literal_string(string_length)?;
let byte = reader.read_u8()?;
assert::int(byte, 0, "Null terminator byte after string")?;
strings.push(string.clone());
}
reader.align(0x80)?;
reader.strings = strings;
Ok(Self)
}
fn serialize(&self, builder: &mut DataBuilder) -> Result<()> {
let mut strings = std::mem::take(&mut builder.string_placeholders);
strings.sort_unstable_by(|a, b| a.string.cmp(&b.string));
let count = count_unique_strings(&strings);
builder.write_usize(count)?;
let pointer_list_start = builder.len();
for _ in 0..count {
builder.write_u32(0xDEAD_C0DE);
}
let mut string = None;
let mut string_position = 0xDEAD_C0DE;
let mut index = 0;
for placeholder in strings {
if string.as_ref() == Some(&placeholder.string) {
overwrite_placeholder(builder, &placeholder, string_position, index - 1)?;
continue;
}
builder.align(ALIGNMENT);
builder.overwrite_pointer_with_cur_pos(pointer_list_start, index)?;
builder.write_usize(placeholder.string.len())?;
string_position = builder.len();
builder.write_literal_string(&placeholder.string);
builder.write_u8(0);
overwrite_placeholder(builder, &placeholder, string_position, index)?;
index += 1;
string = Some(placeholder.string);
}
builder.align(0x80);
Ok(())
}
}
#[derive(Debug)]
pub struct StringPlaceholder {
pub placeholder_position: u32,
pub string: String,
pub write_id: bool,
}
fn count_unique_strings(sorted_vec: &[StringPlaceholder]) -> usize {
if sorted_vec.is_empty() {
return 0;
}
let mut count = 1;
let mut prev = &sorted_vec[0].string;
for item in &sorted_vec[1..] {
if &item.string != prev {
count += 1;
prev = &item.string;
}
}
count
}
fn overwrite_placeholder(
builder: &mut DataBuilder,
placeholder: &StringPlaceholder,
string_position: u32,
index: usize,
) -> Result<()> {
let number: u32 = if placeholder.write_id {
index as u32
} else {
string_position
};
builder.overwrite_u32(number, placeholder.placeholder_position)?;
Ok(())
}