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:
parent
4a7f95d081
commit
9aa09343c5
8 changed files with 457 additions and 109 deletions
|
@ -10,6 +10,7 @@ license = "AGPL-3.0"
|
|||
|
||||
[dependencies]
|
||||
rusb = "0.9.3"
|
||||
translit = "0.5.0"
|
||||
|
||||
[dependencies.minidisc-rs]
|
||||
path = "minidisc-rs"
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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(¤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())
|
||||
}
|
||||
}
|
||||
|
|
273
minidisc-rs/src/netmd/mappings.rs
Normal file
273
minidisc-rs/src/netmd/mappings.rs
Normal 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(), "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<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()});
|
|
@ -2,3 +2,4 @@ mod base;
|
|||
pub mod interface;
|
||||
mod query_utils;
|
||||
mod utils;
|
||||
mod mappings;
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
12
src/main.rs
12
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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue