1
0
Fork 0
mirror of https://github.com/G2-Games/minidisc-cli.git synced 2025-05-02 01:32:54 -05:00

Added mappings file, implemented sanitize_full_width_title

This commit is contained in:
G2-Games 2023-09-25 20:33:43 -05:00
parent 4a7f95d081
commit 9aa09343c5
8 changed files with 457 additions and 109 deletions

View file

@ -10,6 +10,7 @@ license = "AGPL-3.0"
[dependencies]
rusb = "0.9.3"
translit = "0.5.0"
[dependencies.minidisc-rs]
path = "minidisc-rs"

View file

@ -16,4 +16,6 @@ encoding_rs = "0.8.33"
nofmt = "1.0.0"
once_cell = "1.18.0"
rusb = "0.9.3"
translit = "0.5.0"
unicode-jp = "0.4.0"

View file

@ -1,10 +1,12 @@
use crate::netmd::query_utils::{format_query, scan_query};
use crate::netmd::utils::{length_after_encoding_to_jis, half_width_to_full_width_range};
use crate::netmd::base;
use crate::netmd::query_utils::{format_query, scan_query, QueryValue};
use crate::netmd::utils::{
half_width_to_full_width_range, length_after_encoding_to_jis, sanitize_full_width_title,
};
use encoding_rs::*;
use rusb;
use std::collections::HashMap;
use std::error::Error;
use rusb;
#[derive(Copy, Clone)]
enum Action {
@ -182,7 +184,10 @@ impl NetMDInterface {
const MAX_INTERIM_READ_ATTEMPTS: u8 = 4;
const INTERIM_RESPONSE_RETRY_INTERVAL: u32 = 100;
pub fn new(device: rusb::DeviceHandle<rusb::GlobalContext>, descriptor: rusb::DeviceDescriptor) -> Result<Self, Box<dyn Error>> {
pub fn new(
device: rusb::DeviceHandle<rusb::GlobalContext>,
descriptor: rusb::DeviceDescriptor,
) -> Result<Self, Box<dyn Error>> {
let net_md_device = base::NetMD::new(device, descriptor).unwrap();
Ok(NetMDInterface { net_md_device })
}
@ -204,15 +209,14 @@ impl NetMDInterface {
&DescriptorAction::OpenRead,
);
let mut query = format_query(
"1809 00 ff00 0000 0000".to_string(),
vec![],
vec![],
)?;
let mut query = format_query("1809 00 ff00 0000 0000".to_string(), vec![])?;
let reply = self.send_query(&mut query, false, false)?;
let res = scan_query(reply, "1809 00 1000 %?%? %?%? %w %b %b %b %b %w %*".to_string())?;
let res = scan_query(
reply,
"1809 00 1000 %?%? %?%? %w %b %b %b %b %w %*".to_string(),
)?;
let _descriptor_length = res[0].to_i64().unwrap();
let _generation_id = res[1].to_i64().unwrap();
@ -268,7 +272,8 @@ impl NetMDInterface {
}
let manufacturer_dep_length = self.construct_multibyte(&buffer, 2, &mut buffer_offset);
let _manufacturer_dep_data = &buffer[buffer_offset..buffer_offset + manufacturer_dep_length as usize];
let _manufacturer_dep_data =
&buffer[buffer_offset..buffer_offset + manufacturer_dep_length as usize];
self.change_descriptor_state(&Descriptor::DiscSubunitIdentifier, &DescriptorAction::Close);
@ -301,11 +306,7 @@ impl NetMDInterface {
}
fn change_descriptor_state(&self, descriptor: &Descriptor, action: &DescriptorAction) {
let mut query = format_query(
"1808".to_string(),
vec![],
vec![],
).unwrap();
let mut query = format_query("1808".to_string(), vec![]).unwrap();
query.append(&mut descriptor.get_array());
@ -388,8 +389,7 @@ impl NetMDInterface {
fn playback_control(&self, action: Action) -> Result<(), Box<dyn Error>> {
let mut query = format_query(
"18c3 00 %b 000000".to_string(),
vec![Some(action as i64)],
vec![],
vec![QueryValue::Number(action as i64)],
)?;
let reply = self.send_query(&mut query, false, false)?;
@ -417,11 +417,7 @@ impl NetMDInterface {
//TODO: Implement fix for LAM-1
pub fn stop(&self) -> Result<(), Box<dyn Error>> {
let mut query = format_query(
"18c5 ff 00000000".to_string(),
vec![],
vec![],
)?;
let mut query = format_query("18c5 ff 00000000".to_string(), vec![])?;
let reply = self.send_query(&mut query, false, false)?;
@ -434,7 +430,6 @@ impl NetMDInterface {
let mut query = format_query(
"ff 010c ffff ffff ffff ffff ffff ffff".to_string(),
vec![],
vec![],
)?;
let reply = self.send_query(&mut query, false, false)?;
@ -447,7 +442,6 @@ impl NetMDInterface {
let mut query = format_query(
"ff 0100 ffff ffff ffff ffff ffff ffff".to_string(),
vec![],
vec![],
)?;
let reply = self.send_query(&mut query, false, false)?;
@ -466,12 +460,14 @@ impl NetMDInterface {
let mut query = format_query(
"1809 8001 0230 8800 0030 8804 00 ff00 00000000".to_string(),
vec![],
vec![],
)?;
let reply = self.send_query(&mut query, false, false)?;
let res = scan_query(reply, "1809 8001 0230 8800 0030 8804 00 1000 00090000 %x".to_string())?;
let res = scan_query(
reply,
"1809 8001 0230 8800 0030 8804 00 1000 00090000 %x".to_string(),
)?;
self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close);
@ -497,7 +493,6 @@ impl NetMDInterface {
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)?;
@ -535,8 +530,7 @@ impl NetMDInterface {
);
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![],
vec![QueryValue::Number(p1 as i64), QueryValue::Number(p2 as i64)],
)
.unwrap();
@ -569,7 +563,6 @@ impl NetMDInterface {
let mut query = format_query(
"1809 8001 0430 8802 0030 8805 0030 0003 0030 0002 00 ff00 00000000".to_string(),
vec![],
vec![],
)
.unwrap();
@ -595,14 +588,14 @@ impl NetMDInterface {
}
pub fn eject_disc(&self) -> Result<(), Box<dyn Error>> {
let mut query = format_query("18c1 ff 6000".to_string(), vec![], vec![]).unwrap();
let mut query = format_query("18c1 ff 6000".to_string(), 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 = format_query("18c1 ff 6000".to_string(), vec![], vec![]).unwrap();
let mut query = format_query("18c1 ff 6000".to_string(), vec![]).unwrap();
match self.send_query(&mut query, true, false) {
Ok(_) => Ok(true),
@ -614,8 +607,7 @@ impl NetMDInterface {
pub fn go_to_track(&self, track_number: u16) -> Result<u16, Box<dyn Error>> {
let mut query = format_query(
"1850 ff010000 0000 %w".to_string(),
vec![Some(track_number as i64)],
vec![],
vec![QueryValue::Number(track_number as i64)],
)
.unwrap();
@ -639,13 +631,12 @@ impl NetMDInterface {
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),
QueryValue::Number(track_number as i64),
QueryValue::Number(hour as i64),
QueryValue::Number(minute as i64),
QueryValue::Number(second as i64),
QueryValue::Number(frame as i64),
],
vec![],
)
.unwrap();
@ -661,8 +652,7 @@ impl NetMDInterface {
fn _track_change(&self, direction: Track) -> Result<(), Box<dyn Error>> {
let mut query = format_query(
"1850 ff10 00000000 %w".to_string(),
vec![Some(direction as i64)],
vec![],
vec![QueryValue::Number(direction as i64)],
)
.unwrap();
@ -687,7 +677,7 @@ impl NetMDInterface {
/* Content access and control */
pub fn erase_disc(&self) -> Result<(), Box<dyn Error>> {
let mut query = format_query("1840 ff 0000".to_string(), vec![], vec![]).unwrap();
let mut query = format_query("1840 ff 0000".to_string(), vec![]).unwrap();
let reply = self.send_query(&mut query, false, false)?;
scan_query(reply, "1840 00 0000".to_string())?;
Ok(())
@ -698,7 +688,7 @@ impl NetMDInterface {
pub fn disc_flags(&self) -> Result<u8, Box<dyn Error>> {
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead);
let mut query =
format_query("1806 01101000 ff00 0001000b".to_string(), vec![], vec![]).unwrap();
format_query("1806 01101000 ff00 0001000b".to_string(), vec![]).unwrap();
let reply = self.send_query(&mut query, false, false)?;
@ -715,7 +705,6 @@ impl NetMDInterface {
let mut query = format_query(
"1806 02101001 3000 1000 ff00 00000000".to_string(),
vec![],
vec![],
)
.unwrap();
@ -752,18 +741,20 @@ impl NetMDInterface {
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(),
QueryValue::Number(wchar_value),
QueryValue::Number(remaining as i64),
QueryValue::Number(done as i64),
],
vec![],
)
.unwrap();
let reply = self.send_query(&mut query, false, false)?;
if remaining == 0 {
let res = scan_query(reply, "1806 02201801 00%? 3000 0a00 1000 %w0000 %?%?000a %w %*".to_string())?;
let res = scan_query(
reply,
"1806 02201801 00%? 3000 0a00 1000 %w0000 %?%?000a %w %*".to_string(),
)?;
chunksize = res[0].to_i64().unwrap() as i32;
total = res[1].to_i64().unwrap() as i32;
@ -771,7 +762,10 @@ impl NetMDInterface {
chunksize -= 6;
} else {
let res = scan_query(reply, "1806 02201801 00%? 3000 0a00 1000 %w%?%? %*".to_string())?;
let res = scan_query(
reply,
"1806 02201801 00%? 3000 0a00 1000 %w%?%? %*".to_string(),
)?;
chunksize = res[0].to_i64().unwrap() as i32;
chunk = SHIFT_JIS.decode(&res[1].to_vec().unwrap()).0.into();
}
@ -872,8 +866,6 @@ impl NetMDInterface {
// TODO: Do some error handling here
assert!(track_min <= track_max);
println!("{}, {}", track_min, track_max);
let mut track_list: Vec<u16> = Vec::new();
for track in track_min - 1..track_max {
if track_dict.contains_key(&track) {
@ -898,7 +890,6 @@ impl NetMDInterface {
}
}
println!("{:#?}", result);
Ok(result)
}
@ -911,8 +902,7 @@ impl NetMDInterface {
let mut query = format_query(
"1806 022018%b %w 3000 0a00 ff00 00000000".to_string(),
vec![wchar_value.into(), (track as i64).into()],
vec![],
vec![QueryValue::Number(wchar_value), QueryValue::Number(track as i64)],
)
.unwrap();
@ -939,24 +929,55 @@ impl NetMDInterface {
.into())
}
pub fn set_disc_title(&self, title: String, wchar: bool) -> Result<(), Box<dyn Error>> {
pub fn set_disc_title(&self, title: String, wchar: bool) -> Result<String, Box<dyn Error>> {
let current_title = self._disc_title(wchar)?;
if current_title == title {
return Ok(())
return Ok(current_title);
}
let old_len = length_after_encoding_to_jis(current_title);
let new_len = length_after_encoding_to_jis(title);
let new_title: Vec<u8>;
let old_len = length_after_encoding_to_jis(&current_title);
let wchar_value = match wchar {
true => {
new_title = sanitize_full_width_title(&title, false);
1
},
false => {
}
new_title = Vec::new();
0
},
};
Ok(())
let new_len = new_title.len();
if self.net_md_device.vendor_id() == &0x04dd {
self.change_descriptor_state(&Descriptor::AudioUTOC1TD, &DescriptorAction::OpenWrite)
} else {
self.change_descriptor_state(&Descriptor::DiscTitleTD, &DescriptorAction::Close);
self.change_descriptor_state(&Descriptor::DiscTitleTD, &DescriptorAction::OpenWrite)
}
let mut query = format_query(
"1807 02201801 00%b 3000 0a00 5000 %w 0000 %w %*".to_string(),
vec![
QueryValue::Number(wchar_value),
QueryValue::Number(new_len as i64),
QueryValue::Number(old_len as i64),
QueryValue::Array(new_title),
],
)?;
let reply = self.send_query(&mut query, false, false);
if self.net_md_device.vendor_id() == &0x04dd {
self.change_descriptor_state(&Descriptor::AudioUTOC1TD, &DescriptorAction::Close)
} else {
self.change_descriptor_state(&Descriptor::DiscTitleTD, &DescriptorAction::Close);
self.change_descriptor_state(&Descriptor::DiscTitleTD, &DescriptorAction::OpenRead);
self.change_descriptor_state(&Descriptor::DiscTitleTD, &DescriptorAction::Close);
}
Ok(String::from_utf8(sanitize_full_width_title(&title, true)).unwrap())
}
}

View file

@ -0,0 +1,273 @@
use once_cell::sync::Lazy;
use std::collections::HashMap;
pub const MAPPINGS_JP: Lazy<HashMap<String, String>> = Lazy::new(|| {vec![
("!".to_string(), "".to_string()),
("\"".to_string(), "".to_string()),
("#".to_string(), "".to_string()),
("$".to_string(), "".to_string()),
("%".to_string(), "".to_string()),
("&".to_string(), "".to_string()),
("'".to_string(), "".to_string()),
("(".to_string(), "".to_string()),
(")".to_string(), "".to_string()),
("*".to_string(), "".to_string()),
("+".to_string(), "".to_string()),
(",".to_string(), "".to_string()),
("-".to_string(), "".to_string()),
(".".to_string(), "".to_string()),
("/".to_string(), "".to_string()),
(":".to_string(), "".to_string()),
(";".to_string(), "".to_string()),
("<".to_string(), "".to_string()),
("=".to_string(), "".to_string()),
(">".to_string(), "".to_string()),
("?".to_string(), "".to_string()),
("@".to_string(), "".to_string()),
("A".to_string(), "".to_string()),
("B".to_string(), "".to_string()),
("C".to_string(), "".to_string()),
("D".to_string(), "".to_string()),
("E".to_string(), "".to_string()),
("F".to_string(), "".to_string()),
("G".to_string(), "".to_string()),
("H".to_string(), "".to_string()),
("I".to_string(), "".to_string()),
("J".to_string(), "".to_string()),
("K".to_string(), "".to_string()),
("L".to_string(), "".to_string()),
("M".to_string(), "".to_string()),
("N".to_string(), "".to_string()),
("O".to_string(), "".to_string()),
("P".to_string(), "".to_string()),
("Q".to_string(), "".to_string()),
("R".to_string(), "".to_string()),
("S".to_string(), "".to_string()),
("T".to_string(), "".to_string()),
("U".to_string(), "".to_string()),
("V".to_string(), "".to_string()),
("W".to_string(), "".to_string()),
("X".to_string(), "".to_string()),
("Y".to_string(), "".to_string()),
("Z".to_string(), "".to_string()),
("[".to_string(), "".to_string()),
("\\".to_string(), "".to_string()),
("]".to_string(), "".to_string()),
("^".to_string(), "".to_string()),
("_".to_string(), "_".to_string()),
("`".to_string(), "".to_string()),
("a".to_string(), "".to_string()),
("b".to_string(), "".to_string()),
("c".to_string(), "".to_string()),
("d".to_string(), "".to_string()),
("e".to_string(), "".to_string()),
("f".to_string(), "".to_string()),
("g".to_string(), "".to_string()),
("h".to_string(), "".to_string()),
("i".to_string(), "".to_string()),
("j".to_string(), "".to_string()),
("k".to_string(), "".to_string()),
("l".to_string(), "".to_string()),
("m".to_string(), "".to_string()),
("n".to_string(), "".to_string()),
("o".to_string(), "".to_string()),
("p".to_string(), "".to_string()),
("q".to_string(), "".to_string()),
("r".to_string(), "".to_string()),
("s".to_string(), "".to_string()),
("t".to_string(), "".to_string()),
("u".to_string(), "".to_string()),
("v".to_string(), "".to_string()),
("w".to_string(), "".to_string()),
("x".to_string(), "".to_string()),
("y".to_string(), "".to_string()),
("z".to_string(), "".to_string()),
("{".to_string(), "".to_string()),
("|".to_string(), "".to_string()),
("}".to_string(), "".to_string()),
("~".to_string(), "".to_string()),
(" ".to_string(), "\u{3000}".to_string()),
("0".to_string(), "".to_string()),
("1".to_string(), "".to_string()),
("2".to_string(), "".to_string()),
("3".to_string(), "".to_string()),
("4".to_string(), "".to_string()),
("5".to_string(), "".to_string()),
("6".to_string(), "".to_string()),
("7".to_string(), "".to_string()),
("8".to_string(), "".to_string()),
("9".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ガ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ギ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("グ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ゲ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ゴ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ザ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ジ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ズ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ゼ".to_string(), "".to_string()),
("ソ".to_string(), "".to_string()),
("ゾ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ダ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ヂ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ヅ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("デ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ド".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("バ".to_string(), "".to_string()),
("パ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ビ".to_string(), "".to_string()),
("ピ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ブ".to_string(), "".to_string()),
("プ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ベ".to_string(), "".to_string()),
("ペ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ボ".to_string(), "".to_string()),
("ポ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("ヴ".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string()),
("".to_string(), "".to_string())
].into_iter().collect()});
pub const MAPPINGS_RU: Lazy<HashMap<String, String>> = Lazy::new(|| {vec![
("а".to_string(), "a".to_string()),
("б".to_string(), "b".to_string()),
("в".to_string(), "v".to_string()),
("г".to_string(), "g".to_string()),
("д".to_string(), "d".to_string()),
("е".to_string(), "e".to_string()),
("ё".to_string(), "e".to_string()),
("ж".to_string(), "zh".to_string()),
("з".to_string(), "z".to_string()),
("и".to_string(), "i".to_string()),
("й".to_string(), "i".to_string()),
("к".to_string(), "k".to_string()),
("л".to_string(), "l".to_string()),
("м".to_string(), "m".to_string()),
("н".to_string(), "n".to_string()),
("о".to_string(), "o".to_string()),
("п".to_string(), "p".to_string()),
("р".to_string(), "r".to_string()),
("с".to_string(), "s".to_string()),
("т".to_string(), "t".to_string()),
("у".to_string(), "u".to_string()),
("ф".to_string(), "f".to_string()),
("х".to_string(), "kh".to_string()),
("ц".to_string(), "tc".to_string()),
("ч".to_string(), "ch".to_string()),
("ш".to_string(), "sh".to_string()),
("щ".to_string(), "shch".to_string()),
("ъ".to_string(), "".to_string()),
("ы".to_string(), "y".to_string()),
("ь".to_string(), "'".to_string()),
("э".to_string(), "e".to_string()),
("ю".to_string(), "iu".to_string()),
("я".to_string(), "ia".to_string()),
("А".to_string(), "A".to_string()),
("Б".to_string(), "B".to_string()),
("В".to_string(), "V".to_string()),
("Г".to_string(), "G".to_string()),
("Д".to_string(), "D".to_string()),
("Е".to_string(), "E".to_string()),
("Ё".to_string(), "E".to_string()),
("Ж".to_string(), "Zh".to_string()),
("З".to_string(), "Z".to_string()),
("И".to_string(), "I".to_string()),
("Й".to_string(), "I".to_string()),
("К".to_string(), "K".to_string()),
("Л".to_string(), "L".to_string()),
("М".to_string(), "M".to_string()),
("Н".to_string(), "N".to_string()),
("О".to_string(), "O".to_string()),
("П".to_string(), "P".to_string()),
("Р".to_string(), "R".to_string()),
("С".to_string(), "S".to_string()),
("Т".to_string(), "T".to_string()),
("У".to_string(), "U".to_string()),
("Ф".to_string(), "F".to_string()),
("Х".to_string(), "Kh".to_string()),
("Ц".to_string(), "Tc".to_string()),
("Ч".to_string(), "Ch".to_string()),
("Ш".to_string(), "Sh".to_string()),
("Щ".to_string(), "Shch".to_string()),
("Ъ".to_string(), "".to_string()),
("Ы".to_string(), "Y".to_string()),
("Ь".to_string(), "'".to_string()),
("Э".to_string(), "E".to_string()),
("Ю".to_string(), "Iu".to_string()),
("Я".to_string(), "Ia".to_string())
].into_iter().collect()});
pub const MAPPINGS_DE: Lazy<HashMap<String, String>> = Lazy::new(|| {vec![
("Ä".to_string(), "Ae".to_string()),
("ä".to_string(), "ae".to_string()),
("Ö".to_string(), "Oe".to_string()),
("ö".to_string(), "oe".to_string()),
("Ü".to_string(), "Ue".to_string()),
("ü".to_string(), "ue".to_string()),
("ß".to_string(), "ss".to_string())
].into_iter().collect()});

View file

@ -2,3 +2,4 @@ mod base;
pub mod interface;
mod query_utils;
mod utils;
mod mappings;

View file

@ -25,11 +25,31 @@ const FORMAT_TYPE_LEN_DICT: Lazy<HashMap<char, i32>> = Lazy::new(|| {
const DEBUG: bool = false;
pub enum QueryValue {
Number(i64),
Array(Vec<u8>),
}
impl QueryValue {
pub fn to_vec(&self) -> Result<Vec<u8>, Box<dyn Error>> {
match self {
QueryValue::Array(a) => Ok(a.to_vec()),
_ => Err("QueryValue type mismatch! Expected Vec<u8>, got i64".into()),
}
}
pub fn to_i64(&self) -> Result<i64, Box<dyn Error>> {
match self {
QueryValue::Number(a) => Ok(*a),
_ => Err("QueryValue type mismatch! Expected i64, got Vec<u8>".into()),
}
}
}
/// Formats a query using a standard input to send to the player
pub fn format_query(
format: String,
args: Vec<Option<i64>>,
array_args: Vec<Vec<u8>>,
args: Vec<QueryValue>,
) -> Result<Vec<u8>, Box<dyn Error>> {
if DEBUG {
println!("SENT>>> F: {}", format);
@ -38,7 +58,6 @@ pub fn format_query(
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;
let mut escaped = false;
@ -49,10 +68,10 @@ pub fn format_query(
continue;
}
escaped = false;
let value = arg_stack.next().unwrap().unwrap();
match character {
character if FORMAT_TYPE_LEN_DICT.contains_key(&character) => {
let value = arg_stack.next().unwrap().to_i64().unwrap();
match character {
'b' => result.push(value as u8),
'w' => {
@ -72,7 +91,7 @@ pub fn format_query(
endianness_override = None;
}
character if character == 'x' || character == 's' || character == 'z' => {
let mut array_value = array_arg_stack.next().unwrap();
let mut array_value = arg_stack.next().unwrap().to_vec().unwrap();
let mut array_length = array_value.len();
@ -90,10 +109,11 @@ pub fn format_query(
}
}
character if character == '*' => {
let mut array_value = array_arg_stack.next().unwrap();
let mut array_value = arg_stack.next().unwrap().to_vec().unwrap();
result.append(&mut array_value);
}
character if character == 'B' || character == 'W' => {
let value = arg_stack.next().unwrap().to_i64().unwrap();
let converted = utils::int_to_bcd(value as i32);
if character == 'W' {
result.push(((converted >> 8) & 0xFF) as u8);
@ -124,33 +144,12 @@ pub fn format_query(
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();
) -> Result<Vec<QueryValue>, Box<dyn Error>> {
let mut result: Vec<QueryValue> = Vec::new();
let initial_length = query_result.len();
let mut input_stack = query_result.into_iter();
@ -162,8 +161,6 @@ pub fn scan_query(
// TODO: Find out what this is
input_stack.next();
let mut bloop = 0;
for character in format.chars() {
if escaped {
if endianness_override.is_none() && ['<', '>'].contains(&character) {
@ -183,22 +180,22 @@ pub fn scan_query(
'b' => {
let new_value =
u8::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap());
result.push(QueryResults::Number(new_value as i64));
result.push(QueryValue::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));
result.push(QueryValue::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));
result.push(QueryValue::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));
result.push(QueryValue::Number(new_value));
}
_ => unreachable!(),
};
@ -213,7 +210,7 @@ pub fn scan_query(
for _ in 0..length {
result_buffer.push(input_stack.next().unwrap());
}
result.push(QueryResults::Array(result_buffer))
result.push(QueryValue::Array(result_buffer))
}
character if character == '*' || character == '#' => {
let mut result_buffer: Vec<u8> = Vec::new();
@ -222,16 +219,16 @@ pub fn scan_query(
result_buffer.push(entry);
input_stack.next();
}
result.push(QueryResults::Array(result_buffer));
result.push(QueryValue::Array(result_buffer));
}
character if character == 'B' => {
let v = input_stack.next().unwrap();
result.push(QueryResults::Number(utils::bcd_to_int(v as i32) as i64));
result.push(QueryValue::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));
result.push(QueryValue::Number(utils::bcd_to_int(v) as i64));
}
_ => return Err(format!("Unrecognized format char {}", character).into()),
}

View file

@ -1,6 +1,8 @@
use std::collections::hash_map::HashMap;
use encoding_rs::SHIFT_JIS;
use kana::{ascii2wide, combine, half2kana};
use std::collections::hash_map::HashMap;
use std::error::Error;
use crate::netmd::mappings::{MAPPINGS_JP, MAPPINGS_RU, MAPPINGS_DE};
pub fn bcd_to_int(mut bcd: i32) -> i32 {
let mut value = 0;
@ -68,8 +70,51 @@ pub fn get_bytes<const S: usize>(
Ok(bytes)
}
pub fn length_after_encoding_to_jis(string: String) -> usize {
let new_string = SHIFT_JIS.encode(&string);
pub fn length_after_encoding_to_jis(string: &String) -> usize {
let new_string = SHIFT_JIS.encode(string);
new_string.0.len()
}
pub fn validate_shift_jis(sjis_string: &Vec<u8>) -> Result<(), Box<dyn Error>> {
let (_, _, had_errors) = SHIFT_JIS.decode(sjis_string);
if had_errors {
Err("Not valid SHIFT-JIS".into())
} else {
Ok(())
}
}
// TODO: This function is bad, probably should do the string sanitization in the frontend
pub fn sanitize_full_width_title(title: &String, just_remap: bool) -> Vec<u8> {
let new_title: String = title
.chars()
.map(|character| {
match MAPPINGS_JP.get(&character.to_string()) {
Some(string) => string.clone(),
None => character.to_string().clone()
}.to_string()
})
.map(|character| {
match MAPPINGS_RU.get(&character.to_string()) {
Some(string) => string.clone(),
None => character.to_string().clone()
}.to_string()
})
.map(|character| {
match MAPPINGS_DE.get(&character.to_string()) {
Some(string) => string.clone(),
None => character.to_string().clone()
}.to_string()
})
.collect::<String>();
if just_remap {
return new_title.into();
};
let sjis_string = SHIFT_JIS.encode(&new_title).0;
return sjis_string.into();
}

View file

@ -1,3 +1,5 @@
use std::thread::sleep_ms;
use minidisc_rs::netmd::interface;
use rusb;
@ -29,9 +31,15 @@ fn main() {
player_controller.net_md_device.device_name().clone().unwrap()
);
println!("Track Count: {:?}", player_controller.track_count().unwrap());
println!("Disc Title: {} | {}", player_controller.disc_title(false).unwrap(), player_controller.disc_title(true).unwrap());
//println!("TEST CASE: {:?}", player_controller.disc_subunit_identifier());
println!("TEST CASE: {:?}", player_controller.set_disc_title("latvia ハハハ!はいはいです".to_string(), false));
println!("TEST CASE: {:?}", player_controller.set_disc_title("latvia ハハハ!はいはいです".to_string(), true));
std::thread::sleep(std::time::Duration::from_secs(2));
println!(
"Disc Title: {} | {}",
player_controller.disc_title(false).unwrap(),
player_controller.disc_title(true).unwrap()
);
let _ = player_controller.play();