diff --git a/src/lib.rs b/src/lib.rs index 1140107..5916a5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,10 @@ #![feature(array_chunks)] #![feature(iter_collect_into)] -use std::{collections::HashMap, io::Read}; +use std::{ + collections::HashMap, + io::{self, Read}, +}; use anyhow::{anyhow, Context}; @@ -20,7 +23,126 @@ impl PropertyTree { where R: Read, { - Ok(PropertyTree::None) + let first_byte = reader + .by_ref() + .bytes() + .next() + .ok_or(anyhow!("Unexpected EOF")) + .context("Failed trying to get PropertyTreeType")??; + + match first_byte { + 0 => Ok(PropertyTree::None), + 1 => Self::parse_bool(reader), + 2 => Self::parse_number(reader), + 3 => Ok(PropertyTree::String(Self::parse_string(reader)?)), + 4 => Self::parse_list(reader), + 5 => Self::parse_dictionary(reader), + b => Err(anyhow!("Invalid PropertyTreeType {b} expected <6")), + } + } + + fn parse_dictionary(reader: &mut R) -> anyhow::Result + where + R: Read, + { + // Skip the byte between the PropertyTreeType and the first byte of the length + io::copy(&mut reader.by_ref().take(1), &mut io::sink()) + .context("Failed to skip any-type flag: Likely early EoF")?; + + let elements = Self::parse_unsigned_int(reader)?; + let out = HashMap::with_capacity(elements as usize); + + Ok(PropertyTree::Dictionary(out)) + } + + fn parse_list(_reader: &mut R) -> anyhow::Result + where + R: Read, + { + Ok(PropertyTree::List(Vec::new())) + } + + fn parse_string(reader: &mut R) -> anyhow::Result + where + R: Read, + { + // TODO: Investigate this + let _string_exists = reader + .by_ref() + .bytes() + .next() + .ok_or(anyhow!("Unexpected EoF")) + .context("Failed trying to get bool for string")??; + + let length = Self::parse_space_optimized_unsigned_int(reader) + .context("Failed to get length of string")?; + + let mut string = String::new(); + reader + .by_ref() + .take(length as u64) + .read_to_string(&mut string) + .context("Failed reading string bytes")?; + + // TODO: Handle not enough bytes here + + Ok(string) + } + + /// parses a u32_le + fn parse_unsigned_int(reader: &mut R) -> anyhow::Result + where + R: Read, + { + let mut buf = [0u8; 4]; + reader + .read_exact(&mut buf) + .context("Failed trying to get bytes for an unsigned int")?; + + println!("{buf:?}"); + + Ok(u32::from_le_bytes(buf)) + } + + /// parses a u32_le + fn parse_space_optimized_unsigned_int(reader: &mut R) -> anyhow::Result + where + R: Read, + { + let first_byte = reader + .by_ref() + .bytes() + .next() + .ok_or(anyhow!("Unexpected EoF")) + .context("Failed trying to get bytes for space optimized unsigned int")??; + + Ok(match first_byte { + 255 => Self::parse_unsigned_int(reader).context( + "Failed trying to get full length int from space optimized unsigned int", + )?, + value => value as u32, + }) + } + + fn parse_number(_reader: &mut R) -> anyhow::Result + where + R: Read, + { + Ok(PropertyTree::Number(0.0)) + } + + fn parse_bool(reader: &mut R) -> anyhow::Result + where + R: Read, + { + let first_byte = reader + .by_ref() + .bytes() + .next() + .ok_or(anyhow!("Unexpected EoF")) + .context("Failed trying to get boolean value")??; + + Ok(PropertyTree::Bool(first_byte.to_le() == 1)) } } @@ -49,7 +171,7 @@ impl ModSettings { .by_ref() .bytes() .next() - .ok_or(anyhow!("Unexpected EOF")) + .ok_or(anyhow!("Unexpected EoF")) .context("Failed trying to grab null byte that follows version number"); // Mapping pairs of 2 u8s into single le u16s