mirror of
https://github.com/G2-Games/minidisc-cli.git
synced 2025-04-19 11:42:53 -05:00
Fully implemented everything in query_utils.ts
, ran cargo fmt
This commit is contained in:
parent
e39e95d555
commit
54b0977b44
6 changed files with 415 additions and 142 deletions
|
@ -6,7 +6,6 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bcd-numbers = "1.0.11"
|
||||
encoding_rs = "0.8.33"
|
||||
nofmt = "1.0.0"
|
||||
once_cell = "1.18.0"
|
||||
|
|
|
@ -36,6 +36,11 @@ fn main() {
|
|||
println!("Track Count: {:?}", player_controller.track_count());
|
||||
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() {
|
||||
println!(
|
||||
"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, true).unwrap()
|
||||
);
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
let mut request: [u8; 19] = [0x00, 0x18, 0x06, 0x02, 0x20, 0x18,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::netmd::query_utils::{format_query, scan_query};
|
||||
use crate::netmd::utils;
|
||||
use crate::NetMD;
|
||||
use encoding_rs::*;
|
||||
|
@ -383,8 +384,6 @@ impl NetMDInterface {
|
|||
|
||||
let result = self.send_query(&mut query, false, false)?;
|
||||
|
||||
utils::check_result(result, &[0x18, 0xc5, 0x00, action as u8, 0x00, 0x00, 0x00])?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -409,8 +408,6 @@ impl NetMDInterface {
|
|||
|
||||
let result = self.send_query(&mut query, false, false)?;
|
||||
|
||||
utils::check_result(result, &[0x18, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00])?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -420,13 +417,8 @@ impl NetMDInterface {
|
|||
0xff,
|
||||
];
|
||||
let reply = self.send_query(&mut query, false, false)?;
|
||||
utils::check_result(
|
||||
reply,
|
||||
&[
|
||||
0xff, 0x01, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff,
|
||||
],
|
||||
)
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn release(&self) -> Result<(), Box<dyn Error>> {
|
||||
|
@ -435,13 +427,8 @@ impl NetMDInterface {
|
|||
0xff,
|
||||
];
|
||||
let reply = self.send_query(&mut query, false, false)?;
|
||||
utils::check_result(
|
||||
reply,
|
||||
&[
|
||||
0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff,
|
||||
],
|
||||
)
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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>> {
|
||||
// WARNING: Does not work for all devices. See https://github.com/cybercase/webminidisc/issues/21
|
||||
self.change_descriptor_state(
|
||||
&Descriptor::OperatingStatusBlock,
|
||||
&DescriptorAction::OpenRead,
|
||||
);
|
||||
let mut query = vec![
|
||||
0x18, 0x09, 0x80, 0x01, 0x03, 0x30, 0x88, 0x02, 0x00, 0x30, 0x88, 0x05, 0x00, 0x30,
|
||||
0x88, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
let response = self.send_query(&mut query, false, false)?;
|
||||
let mut query = format_query(
|
||||
"1809 8001 0330 8802 0030 8805 0030 8806 00 ff00 00000000".to_string(),
|
||||
vec![],
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
let reply = self.send_query(&mut query, false, false)?;
|
||||
|
||||
let operating_status = response[27..].to_vec();
|
||||
let status_mode = response[20];
|
||||
let result = scan_query(
|
||||
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);
|
||||
|
||||
|
@ -490,49 +485,48 @@ impl NetMDInterface {
|
|||
return Err("Unparsable operating system".into());
|
||||
}
|
||||
|
||||
let status_bytes = [operating_status[0], operating_status[1]];
|
||||
|
||||
let operating_status_number = u16::from_le_bytes(status_bytes);
|
||||
let operating_status_number =
|
||||
(operating_status[0] as u16) << 8 | operating_status[1] as u16;
|
||||
|
||||
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;
|
||||
|
||||
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(
|
||||
&Descriptor::OperatingStatusBlock,
|
||||
&DescriptorAction::OpenRead,
|
||||
);
|
||||
let mut query = vec![
|
||||
0x18, 0x09, 0x80, 0x01, 0x03, 0x30, 0x00, 0x00, 0x00, 0x30, 0x88, 0x05, 0x00, 0x30,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
let mut query = format_query(
|
||||
"1809 8001 0330 %w 0030 8805 0030 %w 00 ff00 00000000".to_string(),
|
||||
vec![Some(p1 as i64), Some(p2 as i64)],
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
query[6] = p1[0];
|
||||
query[7] = p1[1];
|
||||
query[14] = p2[0];
|
||||
query[15] = p2[1];
|
||||
let reply = self.send_query(&mut query, false, false)?;
|
||||
|
||||
let response = self.send_query(&mut query, false, false)?;
|
||||
|
||||
let playback_status = response[24..].to_vec();
|
||||
let res = scan_query(
|
||||
reply,
|
||||
"1809 8001 0330 %?%? %?%? %?%? %?%? %?%? %? 1000 00%?0000 %x %?".to_string(),
|
||||
);
|
||||
|
||||
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>> {
|
||||
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>> {
|
||||
self.playback_status_query([0x88, 0x02], [0x88, 0x06])
|
||||
self.playback_status_query(0x8802, 0x8806)
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Result<[u16; 5], Box<dyn Error>> {
|
||||
|
@ -541,10 +535,12 @@ impl NetMDInterface {
|
|||
&DescriptorAction::OpenRead,
|
||||
);
|
||||
|
||||
let mut query = vec![
|
||||
0x18, 0x09, 0x80, 0x01, 0x04, 0x30, 0x88, 0x02, 0x00, 0x30, 0x88, 0x05, 0x00, 0x30,
|
||||
0x00, 0x03, 0x00, 0x30, 0x00, 0x02, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
let mut query = format_query(
|
||||
"1809 8001 0430 8802 0030 8805 0030 0003 0030 0002 00 ff00 00000000".to_string(),
|
||||
vec![],
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let reply = match self.send_query(&mut query, false, false) {
|
||||
Ok(result) => result,
|
||||
|
@ -552,19 +548,14 @@ impl NetMDInterface {
|
|||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let track_number = u16::from_be_bytes([reply[35], reply[36]]);
|
||||
|
||||
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 result = scan_query(reply, "1809 8001 0430 %?%? %?%? %?%? %?%? %?%? %?%? %?%? %? %?00 00%?0000 000b 0002 0007 00 %w %B %B %B %B".to_string())?;
|
||||
|
||||
let final_result = [
|
||||
track_number,
|
||||
hour as u16,
|
||||
minute as u16,
|
||||
second as u16,
|
||||
frame as u16,
|
||||
result[0].to_i64().unwrap() as u16,
|
||||
result[1].to_i64().unwrap() as u16,
|
||||
result[2].to_i64().unwrap() as u16,
|
||||
result[3].to_i64().unwrap() as u16,
|
||||
result[4].to_i64().unwrap() as u16,
|
||||
];
|
||||
|
||||
self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close);
|
||||
|
@ -573,13 +564,15 @@ impl NetMDInterface {
|
|||
}
|
||||
|
||||
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)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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) {
|
||||
Ok(_) => Ok(true),
|
||||
Err(error) => Err(error),
|
||||
|
@ -587,18 +580,21 @@ impl NetMDInterface {
|
|||
}
|
||||
|
||||
/* Track control */
|
||||
|
||||
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 bytes = track_number.to_le_bytes();
|
||||
|
||||
query[8] = bytes[1];
|
||||
query[9] = bytes[0];
|
||||
let mut query = format_query(
|
||||
"1850 ff010000 0000 %w".to_string(),
|
||||
vec![Some(track_number as i64)],
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
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(
|
||||
|
@ -609,34 +605,39 @@ impl NetMDInterface {
|
|||
second: u8,
|
||||
frame: u8,
|
||||
) -> Result<u16, Box<dyn Error>> {
|
||||
let mut query = vec![
|
||||
0x18, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0b00, 0b00, 0b00, 0b00, 0b00, 0b00,
|
||||
];
|
||||
|
||||
let bytes = track_number.to_le_bytes();
|
||||
query[8] = bytes[1];
|
||||
query[9] = bytes[0];
|
||||
|
||||
query[10] = utils::bcd_from_byte(hour)?;
|
||||
query[11] = utils::bcd_from_byte(minute)?;
|
||||
query[12] = utils::bcd_from_byte(second)?;
|
||||
query[13] = utils::bcd_from_byte(frame)?;
|
||||
let mut query = format_query(
|
||||
"1850 ff000000 0000 %w %B%B%B%B".to_string(),
|
||||
vec![
|
||||
Some(track_number as i64),
|
||||
Some(hour as i64),
|
||||
Some(minute as i64),
|
||||
Some(second as i64),
|
||||
Some(frame as i64),
|
||||
],
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
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>> {
|
||||
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 direction_bytes = direction_number.to_le_bytes();
|
||||
let reply = self.send_query(&mut query, false, false)?;
|
||||
|
||||
query[8] = direction_bytes[1];
|
||||
query[9] = direction_bytes[0];
|
||||
|
||||
let _ = self.send_query(&mut query, false, false);
|
||||
scan_query(reply, "1850 0010 00000000 %?%?".to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -655,42 +656,49 @@ impl NetMDInterface {
|
|||
|
||||
/* Content access and control */
|
||||
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)?;
|
||||
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
|
||||
// looks like it actually might be a 16 bit integer
|
||||
pub fn disc_flags(&self) -> Result<u8, Box<dyn Error>> {
|
||||
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead);
|
||||
let mut query = vec![
|
||||
0x18, 0x06, 0x01, 0x10, 0x10, 0x00, 0xff, 0x00, 0x00, 0x01, 0x00, 0x0b,
|
||||
];
|
||||
let mut query =
|
||||
format_query("1806 01101000 ff00 0001000b".to_string(), vec![], vec![]).unwrap();
|
||||
|
||||
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);
|
||||
|
||||
Ok(flags)
|
||||
Ok(res[0].to_i64().unwrap() as u8)
|
||||
}
|
||||
|
||||
pub fn track_count(&self) -> Result<u8, Box<dyn Error>> {
|
||||
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead);
|
||||
|
||||
let mut query = vec![
|
||||
0x18, 0x06, 0x02, 0x10, 0x10, 0x01, 0x30, 0x00, 0x10, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
];
|
||||
let mut query = format_query(
|
||||
"1806 02101001 3000 1000 ff00 00000000".to_string(),
|
||||
vec![],
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
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);
|
||||
|
||||
Ok(track_count)
|
||||
Ok(res[0].to_i64().unwrap() as u8)
|
||||
}
|
||||
|
||||
fn _disc_title(&self, wchar: bool) -> Result<String, Box<dyn Error>> {
|
||||
|
@ -705,28 +713,26 @@ impl NetMDInterface {
|
|||
let mut chunk = String::new();
|
||||
|
||||
while done < total {
|
||||
let mut query = vec![
|
||||
0x18, 0x06, 0x02, 0x20, 0x18, 0x01, 0x00, 0b00, 0x30, 0x00, 0x0a, 0x00, 0xff, 0x00,
|
||||
0b00, 0b00, 0b00, 0b00,
|
||||
];
|
||||
|
||||
query[7] = match wchar {
|
||||
let wchar_value = match wchar {
|
||||
true => 1,
|
||||
false => 0,
|
||||
};
|
||||
|
||||
let remain_bytes = remaining.to_le_bytes();
|
||||
query[14] = remain_bytes[0];
|
||||
query[15] = remain_bytes[1];
|
||||
|
||||
let done_bytes = done.to_le_bytes();
|
||||
query[16] = done_bytes[0];
|
||||
query[17] = done_bytes[1];
|
||||
let mut query = format_query(
|
||||
"1806 02201801 00%b 3000 0a00 ff00 %w%w".to_string(),
|
||||
vec![
|
||||
wchar_value.into(),
|
||||
(remaining as i64).into(),
|
||||
(done as i64).into(),
|
||||
],
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let reply = self.send_query(&mut query, false, false)?;
|
||||
|
||||
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]]);
|
||||
|
||||
chunk = SHIFT_JIS.decode(&reply[25..]).0.into();
|
||||
|
@ -865,15 +871,18 @@ impl NetMDInterface {
|
|||
|
||||
/// Gets the title of a track at a specified index
|
||||
pub fn track_title(&self, track: u16, wchar: bool) -> Result<String, Box<dyn Error>> {
|
||||
let mut query = vec![
|
||||
0x18, 0x06, 0x02, 0x20, 0x18, 0b00, 0b00, 0b00, 0x30, 0x00, 0x0a, 0x00, 0xff, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
query[5] = match wchar {
|
||||
let wchar_value = match wchar {
|
||||
true => 3,
|
||||
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 {
|
||||
true => Descriptor::AudioUTOC4TD,
|
||||
false => Descriptor::AudioUTOC1TD,
|
||||
|
@ -881,17 +890,19 @@ impl NetMDInterface {
|
|||
|
||||
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 array_len = u16::from_le_bytes([reply[24], reply[23]]);
|
||||
let title_array = &reply[25..array_len as usize + 25];
|
||||
let res = scan_query(
|
||||
reply,
|
||||
"1806 022018%? %?%? %?%? %?%? 1000 00%?0000 00%?000a %x".to_string(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pub mod base;
|
||||
pub mod interface;
|
||||
pub mod utils;
|
||||
pub mod query_utils;
|
||||
pub mod utils;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::netmd::utils;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::hash_map::HashMap;
|
||||
use std::error::Error;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
// prettier-ignore
|
||||
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;
|
||||
|
||||
/// 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 {
|
||||
println!("SENT>>> F: {}", format);
|
||||
}
|
||||
|
||||
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() {
|
||||
println!("{}", character);
|
||||
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(Vec::new())
|
||||
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);
|
||||
if escaped {
|
||||
if endianness_override.is_none() && ['<', '>'].contains(&character) {
|
||||
endianness_override = Some(character);
|
||||
continue;
|
||||
}
|
||||
escaped = false;
|
||||
|
||||
if character == '?' {
|
||||
input_stack.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,35 @@
|
|||
use std::collections::hash_map::HashMap;
|
||||
use std::error::Error;
|
||||
|
||||
pub fn check_result(result: Vec<u8>, expected: &[u8]) -> Result<(), Box<dyn Error>> {
|
||||
match result.as_slice().eq(expected) {
|
||||
true => Ok(()),
|
||||
false => Err("Response was not as expected!".into()),
|
||||
pub fn bcd_to_int(bcd: i32) -> i32 {
|
||||
let mut original = bcd;
|
||||
let mut value = 0;
|
||||
let mut nibble = 0;
|
||||
while original != 0 {
|
||||
let nibble_value = original & 0xf;
|
||||
original = original >> 4;
|
||||
value += nibble_value * i32::pow(10, nibble);
|
||||
nibble += 1;
|
||||
}
|
||||
|
||||
value
|
||||
}
|
||||
|
||||
pub fn byte_from_bcd(byte: u8) -> Result<u8, Box<dyn Error>> {
|
||||
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 lower = byte & 0x0F;
|
||||
|
||||
|
@ -23,7 +44,7 @@ pub fn byte_from_bcd(byte: u8) -> Result<u8, Box<dyn Error>> {
|
|||
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 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())
|
||||
.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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue