Fully implemented everything in query_utils.ts, ran cargo fmt

This commit is contained in:
G2-Games 2023-09-25 01:33:57 -05:00
parent e39e95d555
commit 54b0977b44
6 changed files with 415 additions and 142 deletions

View file

@ -6,7 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bcd-numbers = "1.0.11"
encoding_rs = "0.8.33" encoding_rs = "0.8.33"
nofmt = "1.0.0" nofmt = "1.0.0"
once_cell = "1.18.0" once_cell = "1.18.0"

View file

@ -36,6 +36,11 @@ fn main() {
println!("Track Count: {:?}", player_controller.track_count()); println!("Track Count: {:?}", player_controller.track_count());
println!("Disc Title: {:?}", player_controller.disc_title(false)); println!("Disc Title: {:?}", player_controller.disc_title(false));
println!("TEST CASE: {:?}", player_controller.operating_status());
let _ = player_controller.play();
/*
for i in 0..player_controller.track_count().unwrap() { for i in 0..player_controller.track_count().unwrap() {
println!( println!(
"Track {: >2}: {: >21} | {}", "Track {: >2}: {: >21} | {}",
@ -43,7 +48,7 @@ fn main() {
player_controller.track_title(i as u16, false).unwrap(), player_controller.track_title(i as u16, false).unwrap(),
player_controller.track_title(i as u16, true).unwrap() player_controller.track_title(i as u16, true).unwrap()
); );
} }*/
/* /*
let mut request: [u8; 19] = [0x00, 0x18, 0x06, 0x02, 0x20, 0x18, let mut request: [u8; 19] = [0x00, 0x18, 0x06, 0x02, 0x20, 0x18,

View file

@ -1,3 +1,4 @@
use crate::netmd::query_utils::{format_query, scan_query};
use crate::netmd::utils; use crate::netmd::utils;
use crate::NetMD; use crate::NetMD;
use encoding_rs::*; use encoding_rs::*;
@ -383,8 +384,6 @@ impl NetMDInterface {
let result = self.send_query(&mut query, false, false)?; let result = self.send_query(&mut query, false, false)?;
utils::check_result(result, &[0x18, 0xc5, 0x00, action as u8, 0x00, 0x00, 0x00])?;
Ok(()) Ok(())
} }
@ -409,8 +408,6 @@ impl NetMDInterface {
let result = self.send_query(&mut query, false, false)?; let result = self.send_query(&mut query, false, false)?;
utils::check_result(result, &[0x18, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00])?;
Ok(()) Ok(())
} }
@ -420,13 +417,8 @@ impl NetMDInterface {
0xff, 0xff,
]; ];
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
utils::check_result(
reply, Ok(())
&[
0xff, 0x01, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff,
],
)
} }
fn release(&self) -> Result<(), Box<dyn Error>> { fn release(&self) -> Result<(), Box<dyn Error>> {
@ -435,13 +427,8 @@ impl NetMDInterface {
0xff, 0xff,
]; ];
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
utils::check_result(
reply, Ok(())
&[
0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff,
],
)
} }
fn status(&self) -> Result<Vec<u8>, Box<dyn Error>> { fn status(&self) -> Result<Vec<u8>, Box<dyn Error>> {
@ -471,18 +458,26 @@ impl NetMDInterface {
} }
fn full_operating_status(&self) -> Result<(u8, u16), Box<dyn Error>> { fn full_operating_status(&self) -> Result<(u8, u16), Box<dyn Error>> {
// WARNING: Does not work for all devices. See https://github.com/cybercase/webminidisc/issues/21
self.change_descriptor_state( self.change_descriptor_state(
&Descriptor::OperatingStatusBlock, &Descriptor::OperatingStatusBlock,
&DescriptorAction::OpenRead, &DescriptorAction::OpenRead,
); );
let mut query = vec![ let mut query = format_query(
0x18, 0x09, 0x80, 0x01, 0x03, 0x30, 0x88, 0x02, 0x00, 0x30, 0x88, 0x05, 0x00, 0x30, "1809 8001 0330 8802 0030 8805 0030 8806 00 ff00 00000000".to_string(),
0x88, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, vec![],
]; vec![],
let response = self.send_query(&mut query, false, false)?; )
.unwrap();
let reply = self.send_query(&mut query, false, false)?;
let operating_status = response[27..].to_vec(); let result = scan_query(
let status_mode = response[20]; reply,
"1809 8001 0330 8802 0030 8805 0030 8806 00 1000 00%?0000 00%b 8806 %x".to_string(),
)?;
let operating_status = result[1].to_vec().unwrap();
let status_mode = result[0].to_i64().unwrap() as u8;
self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close); self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close);
@ -490,49 +485,48 @@ impl NetMDInterface {
return Err("Unparsable operating system".into()); return Err("Unparsable operating system".into());
} }
let status_bytes = [operating_status[0], operating_status[1]]; let operating_status_number =
(operating_status[0] as u16) << 8 | operating_status[1] as u16;
let operating_status_number = u16::from_le_bytes(status_bytes);
Ok((status_mode, operating_status_number)) Ok((status_mode, operating_status_number))
} }
fn operating_status(&self) -> Result<u16, Box<dyn Error>> { pub fn operating_status(&self) -> Result<u16, Box<dyn Error>> {
let status = self.full_operating_status()?.1; let status = self.full_operating_status()?.1;
Ok(status) Ok(status)
} }
fn playback_status_query(&self, p1: [u8; 2], p2: [u8; 2]) -> Result<Vec<u8>, Box<dyn Error>> { fn playback_status_query(&self, p1: u32, p2: u32) -> Result<Vec<u8>, Box<dyn Error>> {
self.change_descriptor_state( self.change_descriptor_state(
&Descriptor::OperatingStatusBlock, &Descriptor::OperatingStatusBlock,
&DescriptorAction::OpenRead, &DescriptorAction::OpenRead,
); );
let mut query = vec![ let mut query = format_query(
0x18, 0x09, 0x80, 0x01, 0x03, 0x30, 0x00, 0x00, 0x00, 0x30, 0x88, 0x05, 0x00, 0x30, "1809 8001 0330 %w 0030 8805 0030 %w 00 ff00 00000000".to_string(),
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, vec![Some(p1 as i64), Some(p2 as i64)],
]; vec![],
)
.unwrap();
query[6] = p1[0]; let reply = self.send_query(&mut query, false, false)?;
query[7] = p1[1];
query[14] = p2[0];
query[15] = p2[1];
let response = self.send_query(&mut query, false, false)?; let res = scan_query(
reply,
let playback_status = response[24..].to_vec(); "1809 8001 0330 %?%? %?%? %?%? %?%? %?%? %? 1000 00%?0000 %x %?".to_string(),
);
self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close); self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close);
Ok(playback_status) Ok(res.unwrap()[0].to_vec().unwrap())
} }
pub fn playback_status1(&self) -> Result<Vec<u8>, Box<dyn Error>> { pub fn playback_status1(&self) -> Result<Vec<u8>, Box<dyn Error>> {
self.playback_status_query([0x88, 0x01], [0x88, 0x07]) self.playback_status_query(0x8801, 0x8807)
} }
pub fn playback_status2(&self) -> Result<Vec<u8>, Box<dyn Error>> { pub fn playback_status2(&self) -> Result<Vec<u8>, Box<dyn Error>> {
self.playback_status_query([0x88, 0x02], [0x88, 0x06]) self.playback_status_query(0x8802, 0x8806)
} }
pub fn position(&self) -> Result<[u16; 5], Box<dyn Error>> { pub fn position(&self) -> Result<[u16; 5], Box<dyn Error>> {
@ -541,10 +535,12 @@ impl NetMDInterface {
&DescriptorAction::OpenRead, &DescriptorAction::OpenRead,
); );
let mut query = vec![ let mut query = format_query(
0x18, 0x09, 0x80, 0x01, 0x04, 0x30, 0x88, 0x02, 0x00, 0x30, 0x88, 0x05, 0x00, 0x30, "1809 8001 0430 8802 0030 8805 0030 0003 0030 0002 00 ff00 00000000".to_string(),
0x00, 0x03, 0x00, 0x30, 0x00, 0x02, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, vec![],
]; vec![],
)
.unwrap();
let reply = match self.send_query(&mut query, false, false) { let reply = match self.send_query(&mut query, false, false) {
Ok(result) => result, Ok(result) => result,
@ -552,19 +548,14 @@ impl NetMDInterface {
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
let track_number = u16::from_be_bytes([reply[35], reply[36]]); let result = scan_query(reply, "1809 8001 0430 %?%? %?%? %?%? %?%? %?%? %?%? %?%? %? %?00 00%?0000 000b 0002 0007 00 %w %B %B %B %B".to_string())?;
let hour = utils::byte_from_bcd(reply[37])?;
let minute = utils::byte_from_bcd(reply[38])?;
let second = utils::byte_from_bcd(reply[39])?;
let frame = utils::byte_from_bcd(reply[40])?;
let final_result = [ let final_result = [
track_number, result[0].to_i64().unwrap() as u16,
hour as u16, result[1].to_i64().unwrap() as u16,
minute as u16, result[2].to_i64().unwrap() as u16,
second as u16, result[3].to_i64().unwrap() as u16,
frame as u16, result[4].to_i64().unwrap() as u16,
]; ];
self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close); self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close);
@ -573,13 +564,15 @@ impl NetMDInterface {
} }
pub fn eject_disc(&self) -> Result<(), Box<dyn Error>> { pub fn eject_disc(&self) -> Result<(), Box<dyn Error>> {
let mut query = vec![0x18, 0xc1, 0xff, 0x60, 0x00]; let mut query = format_query("18c1 ff 6000".to_string(), vec![], vec![]).unwrap();
let _reply = self.send_query(&mut query, false, false)?; let _reply = self.send_query(&mut query, false, false)?;
Ok(()) Ok(())
} }
pub fn can_eject_disc(&self) -> Result<bool, Box<dyn Error>> { pub fn can_eject_disc(&self) -> Result<bool, Box<dyn Error>> {
let mut query = vec![0x18, 0xc1, 0xff, 0x60, 0x00]; let mut query = format_query("18c1 ff 6000".to_string(), vec![], vec![]).unwrap();
match self.send_query(&mut query, true, false) { match self.send_query(&mut query, true, false) {
Ok(_) => Ok(true), Ok(_) => Ok(true),
Err(error) => Err(error), Err(error) => Err(error),
@ -587,18 +580,21 @@ impl NetMDInterface {
} }
/* Track control */ /* Track control */
pub fn go_to_track(&self, track_number: u16) -> Result<u16, Box<dyn Error>> { pub fn go_to_track(&self, track_number: u16) -> Result<u16, Box<dyn Error>> {
let mut query = vec![0x18, 0x50, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0b00, 0b00]; let mut query = format_query(
"1850 ff010000 0000 %w".to_string(),
let bytes = track_number.to_le_bytes(); vec![Some(track_number as i64)],
vec![],
query[8] = bytes[1]; )
query[9] = bytes[0]; .unwrap();
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
Ok(u16::from_be_bytes([reply[8], reply[9]])) let res = scan_query(reply, "1850 00010000 0000 %w".to_string())?;
let value = res[0].to_i64()?;
Ok(value as u16)
} }
pub fn go_to_time( pub fn go_to_time(
@ -609,34 +605,39 @@ impl NetMDInterface {
second: u8, second: u8,
frame: u8, frame: u8,
) -> Result<u16, Box<dyn Error>> { ) -> Result<u16, Box<dyn Error>> {
let mut query = vec![ let mut query = format_query(
0x18, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0b00, 0b00, 0b00, 0b00, 0b00, 0b00, "1850 ff000000 0000 %w %B%B%B%B".to_string(),
]; vec![
Some(track_number as i64),
let bytes = track_number.to_le_bytes(); Some(hour as i64),
query[8] = bytes[1]; Some(minute as i64),
query[9] = bytes[0]; Some(second as i64),
Some(frame as i64),
query[10] = utils::bcd_from_byte(hour)?; ],
query[11] = utils::bcd_from_byte(minute)?; vec![],
query[12] = utils::bcd_from_byte(second)?; )
query[13] = utils::bcd_from_byte(frame)?; .unwrap();
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
Ok(u16::from_be_bytes([reply[8], reply[9]])) let res = scan_query(reply, "1850 00000000 %?%? %w %B%B%B%B".to_string())?;
let value = res[0].to_i64()?;
Ok(value as u16)
} }
fn _track_change(&self, direction: Track) -> Result<(), Box<dyn Error>> { fn _track_change(&self, direction: Track) -> Result<(), Box<dyn Error>> {
let mut query = vec![0x18, 0x50, 0xff, 0x10, 0x00, 0x00, 0x00, 0x00, 0b00, 0b00]; let mut query = format_query(
"1850 ff10 00000000 %w".to_string(),
vec![Some(direction as i64)],
vec![],
)
.unwrap();
let direction_number = direction as u16; let reply = self.send_query(&mut query, false, false)?;
let direction_bytes = direction_number.to_le_bytes();
query[8] = direction_bytes[1]; scan_query(reply, "1850 0010 00000000 %?%?".to_string())?;
query[9] = direction_bytes[0];
let _ = self.send_query(&mut query, false, false);
Ok(()) Ok(())
} }
@ -655,42 +656,49 @@ impl NetMDInterface {
/* Content access and control */ /* Content access and control */
pub fn erase_disc(&self) -> Result<(), Box<dyn Error>> { pub fn erase_disc(&self) -> Result<(), Box<dyn Error>> {
let mut query = vec![0x18, 0x40, 0xff, 0x00, 0x00]; let mut query = format_query("1840 ff 0000".to_string(), vec![], vec![]).unwrap();
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
utils::check_result(reply, &[0x18, 0x40, 0x00, 0x00, 0x00]) scan_query(reply, "1840 00 0000".to_string())?;
Ok(())
} }
// TODO: Ensure this is returning the correct value, it // TODO: Ensure this is returning the correct value, it
// looks like it actually might be a 16 bit integer // looks like it actually might be a 16 bit integer
pub fn disc_flags(&self) -> Result<u8, Box<dyn Error>> { pub fn disc_flags(&self) -> Result<u8, Box<dyn Error>> {
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead);
let mut query = vec![ let mut query =
0x18, 0x06, 0x01, 0x10, 0x10, 0x00, 0xff, 0x00, 0x00, 0x01, 0x00, 0x0b, format_query("1806 01101000 ff00 0001000b".to_string(), vec![], vec![]).unwrap();
];
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
let flags = reply[12]; let res = scan_query(reply, "1806 01101000 1000 0001000b %b".to_string()).unwrap();
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::Close); self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::Close);
Ok(flags) Ok(res[0].to_i64().unwrap() as u8)
} }
pub fn track_count(&self) -> Result<u8, Box<dyn Error>> { pub fn track_count(&self) -> Result<u8, Box<dyn Error>> {
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead);
let mut query = vec![ let mut query = format_query(
0x18, 0x06, 0x02, 0x10, 0x10, 0x01, 0x30, 0x00, 0x10, 0x00, 0xff, 0x00, 0x00, 0x00, "1806 02101001 3000 1000 ff00 00000000".to_string(),
0x00, 0x00, vec![],
]; vec![],
)
.unwrap();
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
let track_count = reply[24]; let res = scan_query(
reply,
"1806 02101001 %?%? %?%? 1000 00%?0000 0006 0010000200%b".to_string(),
)
.unwrap();
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::Close); self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::Close);
Ok(track_count) Ok(res[0].to_i64().unwrap() as u8)
} }
fn _disc_title(&self, wchar: bool) -> Result<String, Box<dyn Error>> { fn _disc_title(&self, wchar: bool) -> Result<String, Box<dyn Error>> {
@ -705,28 +713,26 @@ impl NetMDInterface {
let mut chunk = String::new(); let mut chunk = String::new();
while done < total { while done < total {
let mut query = vec![ let wchar_value = match wchar {
0x18, 0x06, 0x02, 0x20, 0x18, 0x01, 0x00, 0b00, 0x30, 0x00, 0x0a, 0x00, 0xff, 0x00,
0b00, 0b00, 0b00, 0b00,
];
query[7] = match wchar {
true => 1, true => 1,
false => 0, false => 0,
}; };
let remain_bytes = remaining.to_le_bytes(); let mut query = format_query(
query[14] = remain_bytes[0]; "1806 02201801 00%b 3000 0a00 ff00 %w%w".to_string(),
query[15] = remain_bytes[1]; vec![
wchar_value.into(),
let done_bytes = done.to_le_bytes(); (remaining as i64).into(),
query[16] = done_bytes[0]; (done as i64).into(),
query[17] = done_bytes[1]; ],
vec![],
)
.unwrap();
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
if remaining == 0 { if remaining == 0 {
chunksize = u16::from_le_bytes([reply[13], reply[14]]); let res = chunksize = u16::from_le_bytes([reply[13], reply[14]]);
total = u16::from_le_bytes([reply[22], reply[23]]); total = u16::from_le_bytes([reply[22], reply[23]]);
chunk = SHIFT_JIS.decode(&reply[25..]).0.into(); chunk = SHIFT_JIS.decode(&reply[25..]).0.into();
@ -865,15 +871,18 @@ impl NetMDInterface {
/// Gets the title of a track at a specified index /// Gets the title of a track at a specified index
pub fn track_title(&self, track: u16, wchar: bool) -> Result<String, Box<dyn Error>> { pub fn track_title(&self, track: u16, wchar: bool) -> Result<String, Box<dyn Error>> {
let mut query = vec![ let wchar_value = match wchar {
0x18, 0x06, 0x02, 0x20, 0x18, 0b00, 0b00, 0b00, 0x30, 0x00, 0x0a, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00,
];
query[5] = match wchar {
true => 3, true => 3,
false => 2, false => 2,
}; };
let mut query = format_query(
"1806 022018%b %w 3000 0a00 ff00 00000000".to_string(),
vec![wchar_value.into(), (track as i64).into()],
vec![],
)
.unwrap();
let descriptor_type = match wchar { let descriptor_type = match wchar {
true => Descriptor::AudioUTOC4TD, true => Descriptor::AudioUTOC4TD,
false => Descriptor::AudioUTOC1TD, false => Descriptor::AudioUTOC1TD,
@ -881,17 +890,19 @@ impl NetMDInterface {
self.change_descriptor_state(&descriptor_type, &DescriptorAction::OpenRead); self.change_descriptor_state(&descriptor_type, &DescriptorAction::OpenRead);
let track_bytes = track.to_le_bytes();
query[6] = track_bytes[1];
query[7] = track_bytes[0];
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
let array_len = u16::from_le_bytes([reply[24], reply[23]]); let res = scan_query(
let title_array = &reply[25..array_len as usize + 25]; reply,
"1806 022018%? %?%? %?%? %?%? 1000 00%?0000 00%?000a %x".to_string(),
)
.unwrap();
self.change_descriptor_state(&descriptor_type, &DescriptorAction::Close); self.change_descriptor_state(&descriptor_type, &DescriptorAction::Close);
Ok(SHIFT_JIS.decode(title_array).0.to_string()) Ok(encoding_rs::SHIFT_JIS
.decode(&res[0].to_vec().unwrap())
.0
.into())
} }
} }

View file

@ -1,4 +1,4 @@
pub mod base; pub mod base;
pub mod interface; pub mod interface;
pub mod utils;
pub mod query_utils; pub mod query_utils;
pub mod utils;

View file

@ -1,6 +1,7 @@
use crate::netmd::utils;
use once_cell::sync::Lazy;
use std::collections::hash_map::HashMap; use std::collections::hash_map::HashMap;
use std::error::Error; use std::error::Error;
use once_cell::sync::Lazy;
// prettier-ignore // prettier-ignore
const FORMAT_TYPE_LEN_DICT: Lazy<HashMap<char, i32>> = Lazy::new(|| { const FORMAT_TYPE_LEN_DICT: Lazy<HashMap<char, i32>> = Lazy::new(|| {
@ -25,16 +26,237 @@ const FORMAT_TYPE_LEN_DICT: Lazy<HashMap<char, i32>> = Lazy::new(|| {
const DEBUG: bool = false; const DEBUG: bool = false;
/// Formats a query using a standard input to send to the player /// Formats a query using a standard input to send to the player
pub fn format_query(format: String, args: Vec<i32>) -> Result<Vec<u8>, Box<dyn Error>> { pub fn format_query(
format: String,
args: Vec<Option<i64>>,
array_args: Vec<Vec<u8>>,
) -> Result<Vec<u8>, Box<dyn Error>> {
if DEBUG { if DEBUG {
println!("SENT>>> F: {}", format); println!("SENT>>> F: {}", format);
} }
let mut result: Vec<u8> = Vec::new(); let mut result: Vec<u8> = Vec::new();
let mut half: Option<char> = None;
let mut arg_stack = args.into_iter();
let mut array_arg_stack = array_args.into_iter();
let mut endianness_override: Option<char> = None;
for character in format.into_bytes().into_iter() { let mut escaped = false;
for character in format.chars() {
if escaped {
if endianness_override.is_none() && ['<', '>'].contains(&character) {
endianness_override = Some(character);
continue;
}
escaped = false;
let value = arg_stack.next().unwrap().unwrap();
match character {
character if FORMAT_TYPE_LEN_DICT.contains_key(&character) => {
match character {
'b' => result.push(value as u8),
'w' => {
let mut value_bytes = (value as i16).to_be_bytes().to_vec();
result.append(&mut value_bytes)
}
'd' => {
let mut value_bytes = (value as i32).to_be_bytes().to_vec();
result.append(&mut value_bytes)
}
'q' => {
let mut value_bytes = value.to_be_bytes().to_vec();
result.append(&mut value_bytes)
}
_ => (),
};
endianness_override = None;
}
character if character == 'x' || character == 's' || character == 'z' => {
let mut array_value = array_arg_stack.next().unwrap();
let mut array_length = array_value.len();
if character == 's' {
array_length += 1;
}
if character != 'z' {
result.push(((array_length >> 8) & 0xFF) as u8)
}
result.push((array_length & 0xFF) as u8);
result.append(&mut array_value);
if character == 's' {
result.push(0);
}
}
character if character == '*' => {
let mut array_value = array_arg_stack.next().unwrap();
result.append(&mut array_value);
}
character if character == 'B' || character == 'W' => {
let converted = utils::int_to_bcd(value as i32);
if character == 'W' {
result.push(((converted >> 8) & 0xFF) as u8);
}
result.push((converted & 0xFF) as u8);
}
_ => return Err(format!("Unrecognized format char {}", character).into()),
}
continue;
}
if character == '%' {
escaped = true;
continue;
}
if character == ' ' {
continue;
}
if half.is_none() {
half = Some(character);
} else {
result.push(
u8::from_str_radix(&String::from_iter([half.unwrap(), character]), 16).unwrap(),
);
half = None;
}
}
Ok(result)
}
pub enum QueryResults {
Number(i64),
Array(Vec<u8>),
}
impl QueryResults {
pub fn to_vec(&self) -> Result<Vec<u8>, Box<dyn Error>> {
match self {
QueryResults::Array(a) => Ok(a.to_vec()),
_ => Err("Result was a number".into()),
}
}
pub fn to_i64(&self) -> Result<i64, Box<dyn Error>> {
match self {
QueryResults::Number(a) => Ok(*a),
_ => Err("Result was a number".into()),
}
}
}
/// Scans a result using a standard input to recieve from the player
pub fn scan_query(
query_result: Vec<u8>,
format: String,
) -> Result<Vec<QueryResults>, Box<dyn Error>> {
let mut result: Vec<QueryResults> = Vec::new();
let initial_length = query_result.len();
let mut input_stack = query_result.into_iter();
let mut half: Option<char> = None;
let mut endianness_override: Option<char> = None;
let mut escaped = false;
// Remove an unknown byte at the beginning
// TODO: Find out what this is
input_stack.next();
for character in format.chars() {
println!("{}", character); println!("{}", character);
if escaped {
if endianness_override.is_none() && ['<', '>'].contains(&character) {
endianness_override = Some(character);
continue;
}
escaped = false;
if character == '?' {
input_stack.next();
continue;
} }
Ok(Vec::new()) match character {
character if FORMAT_TYPE_LEN_DICT.contains_key(&character) => {
println!("Character: {}", character);
match character {
'b' => {
let new_value =
u8::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap());
result.push(QueryResults::Number(new_value as i64));
}
'w' => {
let new_value =
i16::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap());
result.push(QueryResults::Number(new_value as i64));
}
'd' => {
let new_value =
i32::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap());
result.push(QueryResults::Number(new_value as i64));
}
'q' => {
let new_value =
i64::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap());
result.push(QueryResults::Number(new_value));
}
_ => unreachable!(),
};
endianness_override = None;
}
character if character == 'x' || character == 's' || character == 'z' => {
let length = match character {
'z' => input_stack.next().unwrap() as u16,
_ => u16::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap()),
};
let mut result_buffer: Vec<u8> = Vec::new();
for _ in 0..length {
result_buffer.push(input_stack.next().unwrap());
}
result.push(QueryResults::Array(result_buffer))
}
character if character == '*' || character == '#' => {
let mut result_buffer: Vec<i64> = Vec::new();
let temp_stack = input_stack.clone();
for entry in temp_stack.take(initial_length as usize) {
result_buffer.push(entry as i64);
}
}
character if character == 'B' => {
let v = input_stack.next().unwrap();
result.push(QueryResults::Number(utils::bcd_to_int(v as i32) as i64));
}
character if character == 'W' => {
let v = (input_stack.next().unwrap() as i32) << 8
| input_stack.next().unwrap() as i32;
result.push(QueryResults::Number(utils::bcd_to_int(v) as i64));
}
_ => return Err(format!("Unrecognized format char {}", character).into()),
}
continue;
}
if character == '%' {
assert_eq!(half, None);
escaped = true;
continue;
}
if character == ' ' {
continue;
}
if half.is_none() {
half = Some(character);
} else {
let input_value = input_stack.next().unwrap();
let format_value =
u8::from_str_radix(&String::from_iter([half.unwrap(), character]), 16).unwrap();
if format_value != input_value {
let i = initial_length - input_stack.len() - 1;
return Err(format!("Format and input mismatch at {i}: expected {format_value:#0x}, got {input_value:#0x} (format {format})").into());
}
half = None;
}
}
assert_eq!(input_stack.len(), 0);
Ok(result)
} }

View file

@ -1,14 +1,35 @@
use std::collections::hash_map::HashMap; use std::collections::hash_map::HashMap;
use std::error::Error; use std::error::Error;
pub fn check_result(result: Vec<u8>, expected: &[u8]) -> Result<(), Box<dyn Error>> { pub fn bcd_to_int(bcd: i32) -> i32 {
match result.as_slice().eq(expected) { let mut original = bcd;
true => Ok(()), let mut value = 0;
false => Err("Response was not as expected!".into()), let mut nibble = 0;
} while original != 0 {
let nibble_value = original & 0xf;
original = original >> 4;
value += nibble_value * i32::pow(10, nibble);
nibble += 1;
} }
pub fn byte_from_bcd(byte: u8) -> Result<u8, Box<dyn Error>> { value
}
pub fn int_to_bcd(mut value: i32) -> i32 {
let mut bcd = 0;
let mut shift = 0;
while value > 0 {
let digit = value % 10;
bcd |= digit << shift;
shift += 4;
value /= 10;
}
bcd
}
pub fn int_from_bcd(byte: u8) -> Result<u8, Box<dyn Error>> {
let upper = (byte & 0xF0) >> 4; let upper = (byte & 0xF0) >> 4;
let lower = byte & 0x0F; let lower = byte & 0x0F;
@ -23,7 +44,7 @@ pub fn byte_from_bcd(byte: u8) -> Result<u8, Box<dyn Error>> {
Ok(upper * 10 + lower) Ok(upper * 10 + lower)
} }
pub fn bcd_from_byte(byte: u8) -> Result<u8, Box<dyn Error>> { pub fn bcd_from_int(byte: u8) -> Result<u8, Box<dyn Error>> {
let mut new_byte: u8 = 0; let mut new_byte: u8 = 0;
let upper = (byte / 10) << 4; let upper = (byte / 10) << 4;
@ -57,3 +78,18 @@ pub fn half_width_to_full_width_range(range: &String) -> String {
.map(|char| mappings.get(&char).unwrap()) .map(|char| mappings.get(&char).unwrap())
.collect() .collect()
} }
pub fn get_bytes<const S: usize>(
iterator: &mut std::vec::IntoIter<u8>,
) -> Result<[u8; S], Box<dyn std::error::Error>> {
let mut bytes = [0; S];
for i in 0..S {
bytes[i] = match iterator.next() {
Some(byte) => byte,
None => return Err("Could not retrieve byte from file".into()),
};
}
Ok(bytes)
}