From 9aa09343c5f47139780f01d5a99a867aab5ee5b6 Mon Sep 17 00:00:00 2001 From: G2-Games Date: Mon, 25 Sep 2023 20:33:43 -0500 Subject: [PATCH] Added mappings file, implemented `sanitize_full_width_title` --- Cargo.toml | 1 + minidisc-rs/Cargo.toml | 2 + minidisc-rs/src/netmd/interface.rs | 151 ++++++++------- minidisc-rs/src/netmd/mappings.rs | 273 +++++++++++++++++++++++++++ minidisc-rs/src/netmd/mod.rs | 1 + minidisc-rs/src/netmd/query_utils.rs | 75 ++++---- minidisc-rs/src/netmd/utils.rs | 51 ++++- src/main.rs | 12 +- 8 files changed, 457 insertions(+), 109 deletions(-) create mode 100644 minidisc-rs/src/netmd/mappings.rs diff --git a/Cargo.toml b/Cargo.toml index e77504f..c1b861b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ license = "AGPL-3.0" [dependencies] rusb = "0.9.3" +translit = "0.5.0" [dependencies.minidisc-rs] path = "minidisc-rs" diff --git a/minidisc-rs/Cargo.toml b/minidisc-rs/Cargo.toml index 6272fa4..320f3d2 100644 --- a/minidisc-rs/Cargo.toml +++ b/minidisc-rs/Cargo.toml @@ -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" diff --git a/minidisc-rs/src/netmd/interface.rs b/minidisc-rs/src/netmd/interface.rs index 2a42934..76b4f66 100644 --- a/minidisc-rs/src/netmd/interface.rs +++ b/minidisc-rs/src/netmd/interface.rs @@ -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, descriptor: rusb::DeviceDescriptor) -> Result> { + pub fn new( + device: rusb::DeviceHandle, + descriptor: rusb::DeviceDescriptor, + ) -> Result> { 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> { 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> { - 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> { - 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> { - 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> { 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> { 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> { - 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> { 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 = 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> { + pub fn set_disc_title(&self, title: String, wchar: bool) -> Result> { 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; + let old_len = length_after_encoding_to_jis(¤t_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()) } } diff --git a/minidisc-rs/src/netmd/mappings.rs b/minidisc-rs/src/netmd/mappings.rs new file mode 100644 index 0000000..0b0568d --- /dev/null +++ b/minidisc-rs/src/netmd/mappings.rs @@ -0,0 +1,273 @@ +use once_cell::sync::Lazy; +use std::collections::HashMap; + +pub const MAPPINGS_JP: Lazy> = 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(), "A".to_string()), + ("B".to_string(), "B".to_string()), + ("C".to_string(), "C".to_string()), + ("D".to_string(), "D".to_string()), + ("E".to_string(), "E".to_string()), + ("F".to_string(), "F".to_string()), + ("G".to_string(), "G".to_string()), + ("H".to_string(), "H".to_string()), + ("I".to_string(), "I".to_string()), + ("J".to_string(), "J".to_string()), + ("K".to_string(), "K".to_string()), + ("L".to_string(), "L".to_string()), + ("M".to_string(), "M".to_string()), + ("N".to_string(), "N".to_string()), + ("O".to_string(), "O".to_string()), + ("P".to_string(), "P".to_string()), + ("Q".to_string(), "Q".to_string()), + ("R".to_string(), "R".to_string()), + ("S".to_string(), "S".to_string()), + ("T".to_string(), "T".to_string()), + ("U".to_string(), "U".to_string()), + ("V".to_string(), "V".to_string()), + ("W".to_string(), "W".to_string()), + ("X".to_string(), "X".to_string()), + ("Y".to_string(), "Y".to_string()), + ("Z".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()), + ("a".to_string(), "a".to_string()), + ("b".to_string(), "b".to_string()), + ("c".to_string(), "c".to_string()), + ("d".to_string(), "d".to_string()), + ("e".to_string(), "e".to_string()), + ("f".to_string(), "f".to_string()), + ("g".to_string(), "g".to_string()), + ("h".to_string(), "h".to_string()), + ("i".to_string(), "i".to_string()), + ("j".to_string(), "j".to_string()), + ("k".to_string(), "k".to_string()), + ("l".to_string(), "l".to_string()), + ("m".to_string(), "m".to_string()), + ("n".to_string(), "n".to_string()), + ("o".to_string(), "o".to_string()), + ("p".to_string(), "p".to_string()), + ("q".to_string(), "q".to_string()), + ("r".to_string(), "r".to_string()), + ("s".to_string(), "s".to_string()), + ("t".to_string(), "t".to_string()), + ("u".to_string(), "u".to_string()), + ("v".to_string(), "v".to_string()), + ("w".to_string(), "w".to_string()), + ("x".to_string(), "x".to_string()), + ("y".to_string(), "y".to_string()), + ("z".to_string(), "z".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(), "0".to_string()), + ("1".to_string(), "1".to_string()), + ("2".to_string(), "2".to_string()), + ("3".to_string(), "3".to_string()), + ("4".to_string(), "4".to_string()), + ("5".to_string(), "5".to_string()), + ("6".to_string(), "6".to_string()), + ("7".to_string(), "7".to_string()), + ("8".to_string(), "8".to_string()), + ("9".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()) +].into_iter().collect()}); + +pub const MAPPINGS_RU: Lazy> = 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> = 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()}); diff --git a/minidisc-rs/src/netmd/mod.rs b/minidisc-rs/src/netmd/mod.rs index 60df41e..ecfc941 100644 --- a/minidisc-rs/src/netmd/mod.rs +++ b/minidisc-rs/src/netmd/mod.rs @@ -2,3 +2,4 @@ mod base; pub mod interface; mod query_utils; mod utils; +mod mappings; diff --git a/minidisc-rs/src/netmd/query_utils.rs b/minidisc-rs/src/netmd/query_utils.rs index e53a83c..c18095c 100644 --- a/minidisc-rs/src/netmd/query_utils.rs +++ b/minidisc-rs/src/netmd/query_utils.rs @@ -25,11 +25,31 @@ const FORMAT_TYPE_LEN_DICT: Lazy> = Lazy::new(|| { const DEBUG: bool = false; +pub enum QueryValue { + Number(i64), + Array(Vec), +} + +impl QueryValue { + pub fn to_vec(&self) -> Result, Box> { + match self { + QueryValue::Array(a) => Ok(a.to_vec()), + _ => Err("QueryValue type mismatch! Expected Vec, got i64".into()), + } + } + + pub fn to_i64(&self) -> Result> { + match self { + QueryValue::Number(a) => Ok(*a), + _ => Err("QueryValue type mismatch! Expected i64, got Vec".into()), + } + } +} + /// Formats a query using a standard input to send to the player pub fn format_query( format: String, - args: Vec>, - array_args: Vec>, + args: Vec, ) -> Result, Box> { if DEBUG { println!("SENT>>> F: {}", format); @@ -38,7 +58,6 @@ pub fn format_query( let mut result: Vec = Vec::new(); let mut half: Option = None; let mut arg_stack = args.into_iter(); - let mut array_arg_stack = array_args.into_iter(); let mut endianness_override: Option = 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), -} - -impl QueryResults { - pub fn to_vec(&self) -> Result, Box> { - match self { - QueryResults::Array(a) => Ok(a.to_vec()), - _ => Err("Result was a number".into()), - } - } - - pub fn to_i64(&self) -> Result> { - 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, format: String, -) -> Result, Box> { - let mut result: Vec = Vec::new(); +) -> Result, Box> { + let mut result: Vec = 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 = 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()), } diff --git a/minidisc-rs/src/netmd/utils.rs b/minidisc-rs/src/netmd/utils.rs index f087a33..4dc0452 100644 --- a/minidisc-rs/src/netmd/utils.rs +++ b/minidisc-rs/src/netmd/utils.rs @@ -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( 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) -> Result<(), Box> { + 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 { + 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::(); + + if just_remap { + return new_title.into(); + }; + + let sjis_string = SHIFT_JIS.encode(&new_title).0; + + return sjis_string.into(); +} diff --git a/src/main.rs b/src/main.rs index 3f44712..edbb4f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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();