mirror of
https://github.com/G2-Games/minidisc-cli.git
synced 2025-04-19 03:32:53 -05:00
Cleaned up old code, added new functions to commands.rs
This commit is contained in:
parent
4151a4f5c0
commit
bf66c59799
6 changed files with 1125 additions and 652 deletions
|
@ -27,7 +27,6 @@ nofmt = "1.0.0"
|
|||
once_cell = "1.18.0"
|
||||
unicode-normalization = "0.1.22"
|
||||
regex = "1.10.2"
|
||||
lazy_static = "1.4.0"
|
||||
cross_usb = "0.3"
|
||||
num-derive = "0.3.3"
|
||||
num-traits = "0.2.14"
|
||||
|
@ -39,6 +38,7 @@ ecb = "0.1"
|
|||
tokio = { version = "1.36", features = ["sync"] }
|
||||
g2-unicode-jp = "0.4.1"
|
||||
thiserror = "1.0.57"
|
||||
phf = { version = "0.11.2", features = ["phf_macros", "macros"] }
|
||||
|
||||
[target.'cfg(target_family = "wasm")'.dependencies]
|
||||
gloo = { version = "0.11.0", features = ["futures"] }
|
||||
|
|
|
@ -5,7 +5,10 @@ use std::error::Error;
|
|||
use std::time::Duration;
|
||||
use cross_usb::Descriptor;
|
||||
|
||||
use super::interface::{MDSession, MDTrack, NetMDInterface, Direction, InterfaceError};
|
||||
use crate::netmd::interface::DiscFlag;
|
||||
use crate::netmd::utils::RawTime;
|
||||
|
||||
use super::interface::{Channels, Encoding, InterfaceError, MDSession, MDTrack, NetMDInterface, TrackFlag};
|
||||
use super::utils::cross_sleep;
|
||||
|
||||
#[derive(FromPrimitive, PartialEq, Eq)]
|
||||
|
@ -34,6 +37,66 @@ pub struct DeviceStatus {
|
|||
pub time: Time,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Track {
|
||||
index: u16,
|
||||
title: String,
|
||||
full_width_title: String,
|
||||
duration: RawTime,
|
||||
channel: Channels,
|
||||
encoding: Encoding,
|
||||
protected: TrackFlag,
|
||||
}
|
||||
|
||||
impl Track {
|
||||
pub fn chars_to_cells(len: usize) -> usize {
|
||||
f32::ceil(len as f32 / 7.0) as usize
|
||||
}
|
||||
|
||||
pub async fn cells_for_title(&mut self) {
|
||||
let encoding_name_correction = match self.encoding {
|
||||
Encoding::SP => 0,
|
||||
_ => 1
|
||||
};
|
||||
|
||||
let full_width_length = Self::chars_to_cells(self.full_width_title.len() * 2);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Group {
|
||||
index: u16,
|
||||
title: Option<String>,
|
||||
full_width_title: Option<String>,
|
||||
tracks: Vec<Track>,
|
||||
}
|
||||
|
||||
pub struct Disc {
|
||||
title: String,
|
||||
full_width_title: String,
|
||||
writeable: bool,
|
||||
write_protected: bool,
|
||||
used: u64,
|
||||
left: u64,
|
||||
total: u64,
|
||||
track_count: u16,
|
||||
groups: Vec<Group>,
|
||||
}
|
||||
|
||||
impl Disc {
|
||||
pub async fn track_count(&self) -> u16 {
|
||||
self.groups.iter()
|
||||
.map(|g| g.tracks.len())
|
||||
.reduce(|acc, s| acc + s)
|
||||
.unwrap() as u16
|
||||
}
|
||||
|
||||
pub async fn tracks(&self) -> Vec<Track> {
|
||||
self.groups.iter()
|
||||
.flat_map(|g| g.tracks.clone())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NetMDContext {
|
||||
interface: NetMDInterface,
|
||||
}
|
||||
|
@ -48,6 +111,7 @@ impl NetMDContext {
|
|||
})
|
||||
}
|
||||
|
||||
/*
|
||||
/// Change to the next track (skip forward)
|
||||
pub async fn next_track(&mut self) -> Result<(), InterfaceError> {
|
||||
self.interface.track_change(Direction::Next).await
|
||||
|
@ -62,6 +126,7 @@ impl NetMDContext {
|
|||
pub async fn restart_track(&mut self) -> Result<(), InterfaceError> {
|
||||
self.interface.track_change(Direction::Restart).await
|
||||
}
|
||||
*/
|
||||
|
||||
pub async fn device_status(&mut self) -> Result<DeviceStatus, Box<dyn Error>> {
|
||||
let status = self.interface.status().await?;
|
||||
|
@ -132,4 +197,72 @@ impl NetMDContext {
|
|||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn list_content(&mut self) -> Result<Disc, Box<dyn Error>> {
|
||||
let flags = self.interface.disc_flags().await?;
|
||||
let title = self.interface.disc_title(false).await?;
|
||||
let full_width_title = self.interface.disc_title(true).await?;
|
||||
let disc_capacity: [RawTime; 3] = self.interface.disc_capacity().await?;
|
||||
let track_count = self.interface.track_count().await?;
|
||||
|
||||
let mut frames_used = disc_capacity[0].as_frames();
|
||||
let mut frames_total = disc_capacity[1].as_frames();
|
||||
let mut frames_left = disc_capacity[2].as_frames();
|
||||
|
||||
// Some devices report the time remaining of the currently selected recording mode. (Sharps)
|
||||
while frames_total > 512 * 60 * 82 {
|
||||
frames_used /= 2;
|
||||
frames_total /= 2;
|
||||
frames_left /= 2;
|
||||
}
|
||||
|
||||
let track_group_list = self.interface.track_group_list().await?;
|
||||
|
||||
let mut groups = vec![];
|
||||
for (index, group) in track_group_list.iter().enumerate() {
|
||||
let mut tracks = vec![];
|
||||
for track in &group.2 {
|
||||
let (encoding, channel) = self.interface.track_encoding(*track).await?;
|
||||
let duration = self.interface.track_length(*track).await?;
|
||||
let flags = self.interface.track_flags(*track).await?;
|
||||
let title = self.interface.track_title(*track, false).await?;
|
||||
let full_width_title = self.interface.track_title(*track, true).await?;
|
||||
|
||||
tracks.push(
|
||||
Track {
|
||||
index: *track,
|
||||
title,
|
||||
full_width_title,
|
||||
duration,
|
||||
channel,
|
||||
encoding,
|
||||
protected: TrackFlag::from_u8(flags).unwrap(),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
groups.push(
|
||||
Group {
|
||||
index: index as u16,
|
||||
title: group.0.clone(),
|
||||
full_width_title: group.1.clone(),
|
||||
tracks
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
let disc = Disc {
|
||||
title,
|
||||
full_width_title,
|
||||
writeable: (flags & DiscFlag::Writable as u8) != 0,
|
||||
write_protected: (flags & DiscFlag::WriteProtected as u8) != 0,
|
||||
used: frames_used,
|
||||
left: frames_left,
|
||||
total: frames_total,
|
||||
track_count,
|
||||
groups
|
||||
};
|
||||
|
||||
Ok(disc)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
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,
|
||||
sanitize_half_width_title, time_to_duration,
|
||||
half_width_to_full_width_range, length_after_encoding_to_sjis, sanitize_full_width_title,
|
||||
sanitize_half_width_title,
|
||||
RawTime,
|
||||
};
|
||||
use cbc::cipher::block_padding::NoPadding;
|
||||
use cbc::cipher::{BlockDecryptMut, BlockEncryptMut, KeyInit, KeyIvInit};
|
||||
|
@ -16,8 +17,6 @@ use thiserror::Error;
|
|||
use std::error::Error;
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::base::NetMD;
|
||||
use super::utils::cross_sleep;
|
||||
|
||||
|
@ -52,7 +51,7 @@ pub enum WireFormat {
|
|||
}
|
||||
|
||||
impl WireFormat {
|
||||
fn frame_size(&self) -> u16 {
|
||||
const fn frame_size(&self) -> u16 {
|
||||
match self {
|
||||
WireFormat::Pcm => 2048,
|
||||
WireFormat::L105kbps => 192,
|
||||
|
@ -60,31 +59,70 @@ impl WireFormat {
|
|||
WireFormat::LP4 => 96,
|
||||
}
|
||||
}
|
||||
|
||||
const fn disc_for_wire(&self) -> DiscFormat {
|
||||
match self {
|
||||
WireFormat::Pcm => DiscFormat::SPStereo,
|
||||
WireFormat::L105kbps => DiscFormat::LP2,
|
||||
WireFormat::LP2 => DiscFormat::LP2,
|
||||
WireFormat::LP4 => DiscFormat::LP4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Encoding {
|
||||
SP = 0x90,
|
||||
LP2 = 0x92,
|
||||
LP4 = 0x93,
|
||||
}
|
||||
|
||||
enum Channels {
|
||||
impl ToString for Encoding {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Encoding::SP => String::from("sp"),
|
||||
Encoding::LP2 => String::from("lp2"),
|
||||
Encoding::LP4 => String::from("lp4"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Channels {
|
||||
Mono = 0x01,
|
||||
Stereo = 0x00,
|
||||
}
|
||||
|
||||
impl ToString for Channels {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Channels::Mono => String::from("mono"),
|
||||
Channels::Stereo => String::from("stereo"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ChannelCount {
|
||||
Mono = 1,
|
||||
Stereo = 2,
|
||||
}
|
||||
|
||||
enum TrackFlag {
|
||||
#[derive(Debug, Clone, Copy, FromPrimitive)]
|
||||
pub enum TrackFlag {
|
||||
Protected = 0x03,
|
||||
Unprotected = 0x00,
|
||||
}
|
||||
|
||||
enum DiscFlag {
|
||||
impl ToString for TrackFlag {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
TrackFlag::Protected => String::from("protected"),
|
||||
TrackFlag::Unprotected => String::from("unprotected"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum DiscFlag {
|
||||
Writable = 0x10,
|
||||
WriteProtected = 0x40,
|
||||
}
|
||||
|
@ -161,15 +199,6 @@ enum NetmdStatus {
|
|||
Interim = 0x0f,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref FRAME_SIZE: HashMap<WireFormat, usize> = HashMap::from([
|
||||
(WireFormat::Pcm, 2048),
|
||||
(WireFormat::LP2, 192),
|
||||
(WireFormat::L105kbps, 152),
|
||||
(WireFormat::LP4, 96),
|
||||
]);
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
#[error("invalid status code")]
|
||||
pub struct StatusError;
|
||||
|
@ -1065,7 +1094,7 @@ impl NetMDInterface {
|
|||
}
|
||||
|
||||
let new_title: Vec<u8>;
|
||||
let old_len = length_after_encoding_to_jis(¤t_title);
|
||||
let old_len = length_after_encoding_to_sjis(¤t_title);
|
||||
|
||||
let wchar_value = match wchar {
|
||||
true => {
|
||||
|
@ -1143,7 +1172,7 @@ impl NetMDInterface {
|
|||
if title == current_title {
|
||||
return Ok(());
|
||||
}
|
||||
length_after_encoding_to_jis(¤t_title) as u16
|
||||
length_after_encoding_to_sjis(¤t_title) as u16
|
||||
}
|
||||
Err(error) if error.to_string() == "Rejected" => 0,
|
||||
Err(error) => return Err(error),
|
||||
|
@ -1232,12 +1261,12 @@ impl NetMDInterface {
|
|||
Ok(res[0].to_vec().unwrap())
|
||||
}
|
||||
|
||||
/// Gets the length of tracks as a [std::time::Duration] from a set
|
||||
/// Gets the length of tracks as a raw duration from a set
|
||||
pub async fn track_lengths(
|
||||
&mut self,
|
||||
tracks: Vec<u16>,
|
||||
) -> Result<Vec<std::time::Duration>, InterfaceError> {
|
||||
let mut times: Vec<std::time::Duration> = vec![];
|
||||
) -> Result<Vec<RawTime>, InterfaceError> {
|
||||
let mut times = vec![];
|
||||
|
||||
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead)
|
||||
.await?;
|
||||
|
@ -1269,8 +1298,12 @@ impl NetMDInterface {
|
|||
.map(|v| v.to_i64().unwrap() as u64)
|
||||
.collect();
|
||||
|
||||
let length = time_to_duration(×_num);
|
||||
times.push(length);
|
||||
times.push(RawTime {
|
||||
hours: times_num[0],
|
||||
minutes: times_num[1],
|
||||
seconds: times_num[2],
|
||||
frames: times_num[3],
|
||||
});
|
||||
}
|
||||
|
||||
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::Close)
|
||||
|
@ -1279,20 +1312,20 @@ impl NetMDInterface {
|
|||
Ok(times)
|
||||
}
|
||||
|
||||
/// Gets the length of a track as a [std::time::Duration]
|
||||
/// Gets the length of a track as a raw duration
|
||||
pub async fn track_length(
|
||||
&mut self,
|
||||
track: u16,
|
||||
) -> Result<std::time::Duration, InterfaceError> {
|
||||
) -> Result<RawTime, InterfaceError> {
|
||||
Ok(self.track_lengths([track].into()).await?[0])
|
||||
}
|
||||
|
||||
/// Gets the encoding of a track (SP, LP2, LP4)
|
||||
pub async fn track_encoding(&mut self, track_number: u16) -> Result<Encoding, InterfaceError> {
|
||||
pub async fn track_encoding(&mut self, track_number: u16) -> Result<(Encoding, Channels), InterfaceError> {
|
||||
let raw_value = self.raw_track_info(track_number, 0x3080, 0x0700).await?;
|
||||
let result = scan_query(raw_value, "07 0004 0110 %b %b".to_string())?;
|
||||
|
||||
let final_encoding = match result[0].to_i64() {
|
||||
let encoding = match result[0].to_i64() {
|
||||
Ok(0x90) => Encoding::SP,
|
||||
Ok(0x92) => Encoding::LP2,
|
||||
Ok(0x93) => Encoding::LP4,
|
||||
|
@ -1300,7 +1333,14 @@ impl NetMDInterface {
|
|||
Err(_) => unreachable!(),
|
||||
};
|
||||
|
||||
Ok(final_encoding)
|
||||
let channels = match result[0].to_i64() {
|
||||
Ok(0x01) => Channels::Stereo,
|
||||
Ok(0x00) => Channels::Mono,
|
||||
Ok(e) => return Err(InterfaceError::InvalidEncoding(e as u8)),
|
||||
Err(_) => unreachable!(),
|
||||
};
|
||||
|
||||
Ok((encoding, channels))
|
||||
}
|
||||
|
||||
/// Gets a track's flags
|
||||
|
@ -1323,36 +1363,34 @@ impl NetMDInterface {
|
|||
}
|
||||
|
||||
/// Gets the disc capacity as a [std::time::Duration]
|
||||
pub async fn disc_capacity(&mut self) -> Result<[std::time::Duration; 3], InterfaceError> {
|
||||
pub async fn disc_capacity(&mut self) -> Result<[RawTime; 3], InterfaceError> {
|
||||
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead)
|
||||
.await?;
|
||||
|
||||
let mut query = format_query("1806 02101000 3080 0300 ff00 00000000".to_string(), vec![])?;
|
||||
let reply = self.send_query(&mut query, false, false).await?;
|
||||
let mut result: [std::time::Duration; 3] = [std::time::Duration::from_secs(0); 3];
|
||||
|
||||
// 8003 changed to %?03 - Panasonic returns 0803 instead. This byte's meaning is unknown
|
||||
let res = scan_query(
|
||||
reply,
|
||||
"1806 02101000 3080 0300 1000 001d0000 001b %?03 0017 8000 0005 %W %B %B %B 0005 %W %B %B %B 0005 %W %B %B %B".to_string()
|
||||
)?; //25^
|
||||
let res_num: Vec<u64> = res
|
||||
.into_iter()
|
||||
.map(|v| v.to_i64().unwrap() as u64)
|
||||
.collect();
|
||||
)?;
|
||||
|
||||
// Create 3 values, `Frames Used`, `Frames Total`, and `Frames Left`
|
||||
for i in 0..3 {
|
||||
let tmp = &res_num[(4 * i)..=(4 * i) + 3];
|
||||
let time_micros =
|
||||
(tmp[0] * 3600000000) + (tmp[1] * 60000000) + (tmp[2] * 1000000) + (tmp[3] * 11600);
|
||||
result[i] = std::time::Duration::from_micros(time_micros);
|
||||
}
|
||||
let res_num: Vec<RawTime> = res
|
||||
.windows(4)
|
||||
.step_by(4)
|
||||
.map(|t| RawTime {
|
||||
hours: t[0].to_i64().unwrap() as u64,
|
||||
minutes: t[1].to_i64().unwrap() as u64,
|
||||
seconds: t[2].to_i64().unwrap() as u64,
|
||||
frames: t[3].to_i64().unwrap() as u64,
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::Close)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
Ok(res_num.try_into().unwrap())
|
||||
}
|
||||
|
||||
pub async fn recording_parameters(&mut self) -> Result<Vec<u8>, InterfaceError> {
|
||||
|
@ -1724,15 +1762,6 @@ pub fn retailmac(key: &[u8], value: &[u8], iv: &[u8; 8]) -> Vec<u8> {
|
|||
end[..8].to_vec()
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref DISC_FOR_WIRE: HashMap<WireFormat, DiscFormat> = HashMap::from([
|
||||
(WireFormat::Pcm, DiscFormat::SPStereo),
|
||||
(WireFormat::LP2, DiscFormat::LP2),
|
||||
(WireFormat::L105kbps, DiscFormat::LP2),
|
||||
(WireFormat::LP4, DiscFormat::LP4),
|
||||
]);
|
||||
}
|
||||
|
||||
pub struct EKBData {
|
||||
chains: [[u8; 16]; 2],
|
||||
depth: i32,
|
||||
|
@ -1811,7 +1840,7 @@ impl MDTrack {
|
|||
}
|
||||
|
||||
pub fn frame_size(&self) -> usize {
|
||||
*FRAME_SIZE.get(&self.format).unwrap()
|
||||
self.format.frame_size() as usize
|
||||
}
|
||||
|
||||
pub fn chunk_size(&self) -> usize {
|
||||
|
@ -1907,7 +1936,7 @@ impl<'a> MDSession<'a> {
|
|||
)
|
||||
.await?;
|
||||
let data_format = track.data_format();
|
||||
let final_disc_format = disc_format.unwrap_or(*DISC_FOR_WIRE.get(&data_format).unwrap());
|
||||
let final_disc_format = disc_format.unwrap_or(data_format.disc_for_wire());
|
||||
|
||||
let (track_index, uuid, ccid) = self
|
||||
.md
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,23 +1,19 @@
|
|||
use crate::netmd::utils;
|
||||
use lazy_static::lazy_static;
|
||||
use std::collections::hash_map::HashMap;
|
||||
use thiserror::Error;
|
||||
|
||||
lazy_static! {
|
||||
/// %b, w, d, q - explained above (can have endiannes overriden by '>' and '<' operators, f. ex. %>d %<q)
|
||||
/// %s - Uint8Array preceded by 2 bytes of length
|
||||
/// %x - Uint8Array preceded by 2 bytes of length
|
||||
/// %z - Uint8Array preceded by 1 byte of length
|
||||
/// %* - raw Uint8Array
|
||||
/// %B - BCD-encoded 1-byte number
|
||||
/// %W - BCD-encoded 2-byte number
|
||||
static ref FORMAT_TYPE_LEN_DICT: HashMap<char, i32> = HashMap::from([
|
||||
('b', 1), // byte
|
||||
('w', 2), // word
|
||||
('d', 4), // doubleword
|
||||
('q', 8), // quadword
|
||||
]);
|
||||
}
|
||||
/// %b, w, d, q - explained above (can have endiannes overriden by '>' and '<' operators, f. ex. %>d %<q)
|
||||
/// %s - Uint8Array preceded by 2 bytes of length
|
||||
/// %x - Uint8Array preceded by 2 bytes of length
|
||||
/// %z - Uint8Array preceded by 1 byte of length
|
||||
/// %* - raw Uint8Array
|
||||
/// %B - BCD-encoded 1-byte number
|
||||
/// %W - BCD-encoded 2-byte number
|
||||
static FORMAT_TYPE_LEN_DICT: phf::Map<char, i32> = phf::phf_map!{
|
||||
'b' => 1, // byte
|
||||
'w' => 2, // word
|
||||
'd' => 4, // doubleword
|
||||
'q' => 8, // quadword
|
||||
};
|
||||
|
||||
const DEBUG: bool = false;
|
||||
|
||||
|
@ -37,11 +33,11 @@ pub enum ValueError {
|
|||
}
|
||||
|
||||
impl QueryValue {
|
||||
pub fn from_array<const S: usize>(value: [u8; S]) -> Self {
|
||||
pub fn _from_array<const S: usize>(value: [u8; S]) -> Self {
|
||||
Self::Array(value.to_vec())
|
||||
}
|
||||
|
||||
pub fn to_array<const S: usize>(&self) -> Result<[u8; S], ValueError> {
|
||||
pub fn _to_array<const S: usize>(&self) -> Result<[u8; S], ValueError> {
|
||||
let mut array = [0u8; S];
|
||||
match self {
|
||||
QueryValue::Array(a) => {
|
||||
|
@ -78,6 +74,20 @@ impl QueryValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryInto<i64> for QueryValue {
|
||||
type Error = ValueError;
|
||||
|
||||
fn try_into(self) -> Result<i64, Self::Error> {
|
||||
match self {
|
||||
QueryValue::Number(a) => Ok(a),
|
||||
_ => Err(ValueError::TypeMismatch {
|
||||
expected: String::from("i64"),
|
||||
actual: format!("{:?}", self)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum QueryError {
|
||||
#[error("unrecognized format character: `{0}`")]
|
||||
|
|
|
@ -8,7 +8,7 @@ use unicode_normalization::UnicodeNormalization;
|
|||
extern crate kana;
|
||||
use kana::*;
|
||||
|
||||
/// Sleep for a specified number of milliseconds on any platform
|
||||
/// Sleep for a specified [Duration] on any platform
|
||||
pub async fn cross_sleep(duration: Duration) {
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
std::thread::sleep(duration);
|
||||
|
@ -75,29 +75,34 @@ pub fn get_bytes<const S: usize>(iterator: &mut IntoIter<u8>) -> Result<[u8; S],
|
|||
Ok(bytes)
|
||||
}
|
||||
|
||||
pub fn length_after_encoding_to_jis(string: &str) -> usize {
|
||||
pub fn length_after_encoding_to_sjis(string: &str) -> usize {
|
||||
let new_string = SHIFT_JIS.encode(string);
|
||||
|
||||
new_string.0.len()
|
||||
}
|
||||
|
||||
pub fn validate_shift_jis(sjis_string: Vec<u8>) -> bool {
|
||||
pub fn validate_sjis(sjis_string: Vec<u8>) -> bool {
|
||||
let (_, _, had_errors) = SHIFT_JIS.decode(&sjis_string);
|
||||
|
||||
had_errors
|
||||
}
|
||||
|
||||
/// Ensure string contains only hardware allowed characters
|
||||
fn check(string: String) -> Option<String> {
|
||||
if MAPPINGS_HW.contains_key(&string) {
|
||||
return Some(MAPPINGS_HW.get(&string).unwrap().to_string());
|
||||
if MAPPINGS_HW.contains_key(string.as_str()) {
|
||||
return Some(MAPPINGS_HW.get(string.as_str()).unwrap().to_string());
|
||||
}
|
||||
let mut ch = string.chars();
|
||||
if (ch.next().unwrap() as u32) < 0x7f || ALLOWED_HW_KANA.contains(&string) {
|
||||
if (ch.next().unwrap() as u32) < 0x7f || ALLOWED_HW_KANA.contains(&string.as_str()) {
|
||||
return Some(string);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn half_width_title_length(title: &str) {
|
||||
|
||||
}
|
||||
|
||||
pub fn sanitize_half_width_title(title: &str) -> Vec<u8> {
|
||||
let mut string_title = wide2ascii(title);
|
||||
string_title = nowidespace(&string_title);
|
||||
|
@ -115,7 +120,7 @@ pub fn sanitize_half_width_title(title: &str) -> Vec<u8> {
|
|||
|
||||
let sjis_string = SHIFT_JIS.encode(&new_title).0;
|
||||
|
||||
if validate_shift_jis(sjis_string.clone().into()) {
|
||||
if validate_sjis(sjis_string.clone().into()) {
|
||||
return agressive_sanitize_title(title).into();
|
||||
}
|
||||
|
||||
|
@ -126,24 +131,25 @@ pub fn sanitize_half_width_title(title: &str) -> Vec<u8> {
|
|||
pub fn sanitize_full_width_title(title: &str, just_remap: bool) -> Vec<u8> {
|
||||
let new_title: String = title
|
||||
.chars()
|
||||
.map(|c| c.to_string())
|
||||
.map(|character| {
|
||||
match MAPPINGS_JP.get(&character.to_string()) {
|
||||
Some(string) => string.clone(),
|
||||
None => character.to_string().clone(),
|
||||
match MAPPINGS_JP.get(character.to_string().as_str()) {
|
||||
Some(string) => string,
|
||||
None => character.as_str(),
|
||||
}
|
||||
.to_string()
|
||||
})
|
||||
.map(|character| {
|
||||
match MAPPINGS_RU.get(&character.to_string()) {
|
||||
Some(string) => string.clone(),
|
||||
None => character.to_string().clone(),
|
||||
match MAPPINGS_RU.get(character.as_str()) {
|
||||
Some(string) => string,
|
||||
None => character.as_str(),
|
||||
}
|
||||
.to_string()
|
||||
})
|
||||
.map(|character| {
|
||||
match MAPPINGS_DE.get(&character.to_string()) {
|
||||
Some(string) => string.clone(),
|
||||
None => character.to_string().clone(),
|
||||
match MAPPINGS_DE.get(character.as_str()) {
|
||||
Some(string) => string,
|
||||
None => character.as_str(),
|
||||
}
|
||||
.to_string()
|
||||
})
|
||||
|
@ -155,7 +161,7 @@ pub fn sanitize_full_width_title(title: &str, just_remap: bool) -> Vec<u8> {
|
|||
|
||||
let sjis_string = SHIFT_JIS.encode(&new_title).0;
|
||||
|
||||
if validate_shift_jis(sjis_string.clone().into()) {
|
||||
if validate_sjis(sjis_string.clone().into()) {
|
||||
return agressive_sanitize_title(title).into();
|
||||
}
|
||||
|
||||
|
@ -173,9 +179,28 @@ pub fn agressive_sanitize_title(title: &str) -> String {
|
|||
.into()
|
||||
}
|
||||
|
||||
pub fn time_to_duration(time: &[u64]) -> std::time::Duration {
|
||||
assert_eq!(time.len(), 4);
|
||||
std::time::Duration::from_micros(
|
||||
(time[0] * 3600000000) + (time[1] * 60000000) + (time[2] * 1000000) + (time[3] * 11600),
|
||||
)
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct RawTime {
|
||||
pub hours: u64,
|
||||
pub minutes: u64,
|
||||
pub seconds: u64,
|
||||
pub frames: u64,
|
||||
}
|
||||
|
||||
impl Into<Duration> for RawTime {
|
||||
fn into(self) -> std::time::Duration {
|
||||
self.as_duration()
|
||||
}
|
||||
}
|
||||
|
||||
impl RawTime {
|
||||
pub fn as_duration(&self) -> Duration {
|
||||
std::time::Duration::from_micros(
|
||||
(self.hours * 3600000000) + (self.minutes * 60000000) + (self.seconds * 1000000) + (self.frames * 11600),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn as_frames(&self) -> u64 {
|
||||
((self.hours * 60 + self.minutes) * 60 + self.seconds) * 512 + self.frames
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue