z_mirror/fmm
git clone https://git.raiguard.me/z_mirror/fmm
216c7c7
rust-ice
1use anyhow:: anyhow; 2use anyhow:: Result ; 3use byteorder::{ LittleEndian , ReadBytesExt }; 4use semver:: Version ; 5use semver:: VersionReq ; 6use std:: collections:: HashMap ; 7use std:: io:: prelude:: * ; 8use std:: io:: Cursor ; 9use std:: io:: Read ; 10use std:: io:: SeekFrom ; 11 12use crate :: types:: ModIdent ; 13 14pub type DatReader =Cursor < Vec < u8 >>; 15 16# [ derive ( Debug )] 17pub enum PropertyTree { 18None , 19Boolean ( bool ), 20Number ( f64 ), 21String ( Option < String >), 22List ( Vec < PropertyTree >), 23Dictionary ( HashMap < String , PropertyTree >), 24} 25 26impl PropertyTree { 27pub fn load ( reader : & mut DatReader ) ->Result < Self > { 28let pt_type = reader. read_u8 () ?; 29// Internal flag that we don't have to care about 30 reader. seek ( SeekFrom :: Current ( 1 )) ?; 31match pt_type{ 320 =>Ok ( Self :: None ), 331 =>Ok ( Self :: Boolean ( read_bool ( reader) ?)), 342 =>Ok ( Self :: Number ( reader. read_f64 ::< LittleEndian >() ?)), 353 =>Ok ( Self :: String ( read_pt_string ( reader) ?)), 364 =>{ 37let length = reader. read_u32 ::< LittleEndian >() ?; 38let mut list =Vec :: with_capacity ( lengthas usize ); 39for _in 0 ..length{ 40read_pt_string ( reader) ?; 41 list. push ( PropertyTree :: load ( reader) ?); 42} 43Ok ( Self :: List ( list)) 44} 455 =>{ 46let length = reader. read_u32 ::< LittleEndian >() ?; 47let mut dict =HashMap :: with_capacity ( lengthas usize ); 48for _in 0 ..length{ 49 dict. insert ( 50read_pt_string ( reader) ? 51. ok_or_else ( ||anyhow! ( "Missing key in PropertyTree Dictionary" )) ?, 52PropertyTree :: load ( reader) ?, 53); 54} 55Ok ( Self :: Dictionary ( dict)) 56} 57 _ =>Err ( anyhow! ( "Invalid data type in PropertyTree: {}" , pt_type)), 58} 59} 60} 61 62pub fn read_bool ( reader : & mut DatReader ) ->Result < bool > { 63match reader. read_u8 () ?{ 640 =>Ok ( false ), 651 =>Ok ( true ), 66 _ =>Err ( anyhow! ( "Invalid boolean representation in PropertyTree." )), 67} 68} 69 70pub fn read_string ( reader : & mut DatReader ) ->Result < String > { 71let scenario_len = reader. read_u8 () ?; 72let mut scenario_name =vec! [ 0 ; scenario_lenas usize ]; 73 reader. read_exact ( & mut scenario_name) ?; 74 75Ok ( String :: from_utf8_lossy ( & scenario_name). to_string ()) 76} 77 78// Strings in PropertyTrees have an extra byte to inform us if they are empty 79pub fn read_pt_string ( reader : & mut DatReader ) ->Result < Option < String >> { 80if read_bool ( reader) ?{ 81Ok ( None ) 82} else { 83read_string ( reader). map ( Some ) 84} 85} 86 87pub fn read_u16_optimized ( reader : & mut DatReader ) ->Result < u16 > { 88let mut version: u16 = reader. read_u8 () ?. into (); 89if version ==255 { 90 version = reader. read_u16 ::< LittleEndian >() ?; 91} 92Ok ( version) 93} 94 95pub fn read_mod ( reader : & mut DatReader ) ->Result < ModIdent > { 96let mod_name =read_string ( reader) ?; 97 98let version_major =read_u16_optimized ( reader) ?; 99let version_minor =read_u16_optimized ( reader) ?; 100let version_patch =read_u16_optimized ( reader) ?; 101 102// We don't care about the CRC 103let _crc = reader. read_u32 ::< LittleEndian >() ?; 104 105Ok ( ModIdent { 106name : mod_name, 107version_req : Some ( VersionReq :: exact ( & Version :: new ( 108 version_majoras u64 , 109 version_minoras u64 , 110 version_patchas u64 , 111))), 112}) 113}