use crate::prelude::*;
use crate::util::init::vec_with_capacity;
use crate::wad::deserialize::reader::DataReader;
use crate::wad::version::GMVersionReq;
use crate::wad::version::LTSBranch::PostLTS;
pub fn check_2022_2(reader: &mut DataReader) -> Result<Option<GMVersionReq>> {
let target_ver = Ok(Some((2022, 2).into()));
let possible_font_count = reader.read_u32()?;
if possible_font_count < 1 {
return Ok(None);
}
let mut first_font_pointer = 0;
for _ in 0..possible_font_count {
let pointer = reader.read_u32()?;
if pointer != 0 {
first_font_pointer = pointer;
break;
}
}
if first_font_pointer == 0 {
return Ok(None);
}
reader.cur_pos = first_font_pointer + 48;
let glyph_count = reader.read_u32()?;
if glyph_count * 4 > reader.chunk.length() {
return Ok(None);
}
if glyph_count == 0 {
log::warn!("Glyph count is zero while detecting FONT_2022.2; may lead to false positives");
return target_ver; }
let mut glyph_pointers: Vec<u32> = vec_with_capacity(glyph_count)?;
for _ in 0..glyph_count {
let pointer = reader.read_u32()?;
if pointer == 0 {
bail!("One of the glyph pointers is null?");
}
glyph_pointers.push(pointer);
}
for pointer in glyph_pointers {
if reader.cur_pos != pointer {
return Ok(None);
}
reader.cur_pos += 14;
let kerning_length = reader.read_u16()?;
reader.cur_pos += u32::from(kerning_length) * 4;
}
target_ver
}
pub fn check_2023_6_and_2024_11(reader: &mut DataReader) -> Result<Option<GMVersionReq>> {
if !reader.general_info.is_version_at_least((2022, 8)) {
return Ok(None); }
if reader.general_info.is_version_at_least((2023, 6))
&& !reader.general_info.is_version_at_least((2024, 6))
{
return Ok(None); }
if reader.general_info.is_version_at_least((2024, 11)) {
return Ok(None); }
let possible_font_count = reader.read_i32()?;
let mut first_two_pointers: Vec<u32> = Vec::with_capacity(2);
for _ in 0..possible_font_count {
let ptr = reader.read_u32()?;
if ptr == 0 {
continue;
}
first_two_pointers.push(ptr);
if first_two_pointers.len() >= 2 {
break;
}
}
if first_two_pointers.is_empty() {
return Ok(None); }
if first_two_pointers.len() == 1 {
first_two_pointers.push(reader.chunk.end_pos - 512);
}
reader.cur_pos = first_two_pointers[0] + 52; if reader.general_info.is_version_at_least((2023, 2, PostLTS)) {
reader.cur_pos += 4; }
let glyph_count = reader.read_u32()?;
if glyph_count * 4 > first_two_pointers[1] - reader.cur_pos || glyph_count < 1 {
return Ok(None);
}
let mut glyph_pointers: Vec<u32> = vec_with_capacity(glyph_count)?;
for _ in 0..glyph_count {
let ptr = reader.read_u32()?;
if ptr == 0 {
bail!("One of the glyph pointers is zero");
}
glyph_pointers.push(ptr);
}
if let Some((i, glyph_pointer)) = glyph_pointers.iter().enumerate().next() {
if reader.cur_pos != *glyph_pointer {
return Ok(None);
}
reader.cur_pos += 14;
let kerning_count = reader.read_u16()?;
let next_glyph_pointer = if i < glyph_pointers.len() - 1 {
glyph_pointers[i + 1]
} else {
first_two_pointers[1]
};
let pointer_after_kerning_list = reader.cur_pos + 4 * u32::from(kerning_count);
if next_glyph_pointer == pointer_after_kerning_list {
return Ok(Some((2023, 6).into())); }
let kerning_count = reader.read_u16()?;
let pointer_after_kerning_list = reader.cur_pos + 4 * u32::from(kerning_count);
if next_glyph_pointer != pointer_after_kerning_list {
log::warn!(
"There appears to be more/fewer values than UnknownAlwaysZero before the kerning \
list in GMFontGlyph; data file potentially corrupted"
);
}
return Ok(Some((2024, 11).into())); }
Ok(Some((2023, 6).into())) }
pub fn check_2024_14(reader: &mut DataReader) -> Result<Option<GMVersionReq>> {
let font_count = reader.read_u32()?;
let mut last_font_position = 0;
for _ in 0..font_count {
let ptr = reader.read_u32()?;
if ptr != 0 {
last_font_position = ptr;
}
}
if last_font_position != 0 {
reader.cur_pos = last_font_position + 56;
let glyph_count = reader.read_u32()?;
reader.cur_pos += (glyph_count - 1) * 4;
reader.cur_pos = reader.read_u32()? + 16;
let kerning_count = reader.read_u16()?;
reader.cur_pos += u32::from(kerning_count) * 4;
}
if reader.cur_pos + 512 > reader.chunk.end_pos {
return Ok(Some((2024, 14).into()));
}
Ok(None)
}