Compare commits
3 Commits
38a770161a
...
687885b88d
Author | SHA1 | Date | |
---|---|---|---|
687885b88d | |||
6a60dec89b | |||
4ca1bfe2c8 |
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -544,6 +544,7 @@ dependencies = [
|
|||||||
"umc_kuwo",
|
"umc_kuwo",
|
||||||
"umc_ncm",
|
"umc_ncm",
|
||||||
"umc_qmc",
|
"umc_qmc",
|
||||||
|
"umc_xmly",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-test",
|
"wasm-bindgen-test",
|
||||||
]
|
]
|
||||||
|
@ -44,9 +44,8 @@ impl ArgsXimalaya {
|
|||||||
_ => bail!("ext not found"),
|
_ => bail!("ext not found"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let mut read_stream = BufReader::with_capacity(cli.buffer_size, File::open(&self.input)?);
|
let mut reader = BufReader::with_capacity(cli.buffer_size, File::open(&self.input)?);
|
||||||
let mut write_stream =
|
let mut writer = BufWriter::with_capacity(cli.buffer_size, File::create(&self.output)?);
|
||||||
BufWriter::with_capacity(cli.buffer_size, File::create(&self.output)?);
|
|
||||||
|
|
||||||
match file_type {
|
match file_type {
|
||||||
XimalayaType::X2M | XimalayaType::X3M => {
|
XimalayaType::X2M | XimalayaType::X3M => {
|
||||||
@ -56,36 +55,36 @@ impl ArgsXimalaya {
|
|||||||
_ => bail!("this should not happen"),
|
_ => bail!("this should not happen"),
|
||||||
};
|
};
|
||||||
let mut header = [0u8; 0x400];
|
let mut header = [0u8; 0x400];
|
||||||
read_stream.read_exact(&mut header)?;
|
reader.read_exact(&mut header)?;
|
||||||
umc_xmly::android::decrypt_android(android_type, &mut header);
|
umc_xmly::android::decrypt_android(android_type, &mut header);
|
||||||
write_stream.write_all(&header)?;
|
writer.write_all(&header)?;
|
||||||
io::copy(&mut read_stream, &mut write_stream)?;
|
io::copy(&mut reader, &mut writer)?;
|
||||||
}
|
}
|
||||||
XimalayaType::XM => {
|
XimalayaType::XM => {
|
||||||
let mut header = vec![0u8; 1024];
|
let mut header = vec![0u8; 1024];
|
||||||
read_stream.read_exact(&mut header)?;
|
reader.read_exact(&mut header)?;
|
||||||
let xm_file = match umc_xmly::pc::Header::from_buffer(&header) {
|
let xm_file = match umc_xmly::pc::Header::from_buffer(&header) {
|
||||||
Ok(hdr) => hdr,
|
Ok(hdr) => hdr,
|
||||||
Err(umc_xmly::XmlyError::MetadataTooSmall(n)) => {
|
Err(umc_xmly::XmlyError::MetadataTooSmall(n)) => {
|
||||||
let old_size = header.len();
|
let old_size = header.len();
|
||||||
header.resize(n, 0);
|
header.resize(n, 0);
|
||||||
read_stream.read_exact(&mut header[old_size..])?;
|
reader.read_exact(&mut header[old_size..])?;
|
||||||
umc_xmly::pc::Header::from_buffer(&header)?
|
umc_xmly::pc::Header::from_buffer(&header)?
|
||||||
}
|
}
|
||||||
Err(err) => bail!("failed to parse file: {err}"),
|
Err(err) => bail!("failed to parse file: {err}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Copy header
|
// Copy header
|
||||||
write_stream.write_all(xm_file.copy_m4a_header().as_slice())?;
|
writer.write_all(xm_file.copy_m4a_header().as_slice())?;
|
||||||
|
|
||||||
// Process encrypted data
|
// Process encrypted data
|
||||||
read_stream.seek(SeekFrom::Start(xm_file.data_start_offset as u64))?;
|
reader.seek(SeekFrom::Start(xm_file.data_start_offset as u64))?;
|
||||||
let mut header = vec![0u8; xm_file.encrypted_header_size];
|
let mut header = vec![0u8; xm_file.encrypted_header_size];
|
||||||
read_stream.read_exact(&mut header[..])?;
|
reader.read_exact(&mut header[..])?;
|
||||||
write_stream.write_all(xm_file.decrypt(&mut header[..])?)?;
|
writer.write_all(xm_file.decrypt(&mut header[..])?)?;
|
||||||
|
|
||||||
// Copy rest of the file
|
// Copy rest of the file
|
||||||
io::copy(&mut read_stream, &mut write_stream)?;
|
io::copy(&mut reader, &mut writer)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ umc_kgm = { path = "../um_crypto/kgm" }
|
|||||||
umc_kuwo = { path = "../um_crypto/kuwo" }
|
umc_kuwo = { path = "../um_crypto/kuwo" }
|
||||||
umc_ncm = { path = "../um_crypto/ncm" }
|
umc_ncm = { path = "../um_crypto/ncm" }
|
||||||
umc_qmc = { path = "../um_crypto/qmc" }
|
umc_qmc = { path = "../um_crypto/qmc" }
|
||||||
|
umc_xmly = { path = "../um_crypto/xmly" }
|
||||||
um_audio = { path = "../um_audio" }
|
um_audio = { path = "../um_audio" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -2,32 +2,18 @@ use umc_kgm::{header::Header, Decipher};
|
|||||||
use wasm_bindgen::prelude::wasm_bindgen;
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
use wasm_bindgen::JsError;
|
use wasm_bindgen::JsError;
|
||||||
|
|
||||||
/// KuGou KGM file header.
|
|
||||||
#[wasm_bindgen(js_name=KuGouHeader)]
|
|
||||||
pub struct JsKuGouHeader(Header);
|
|
||||||
|
|
||||||
#[wasm_bindgen(js_class = KuGouHeader)]
|
|
||||||
impl JsKuGouHeader {
|
|
||||||
/// Parse the KuGou header (0x400 bytes)
|
|
||||||
pub fn parse(header: &[u8]) -> Result<JsKuGouHeader, JsError> {
|
|
||||||
Ok(JsKuGouHeader(
|
|
||||||
Header::from_buffer(header).map_err(JsError::from)?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// KuGou KGM file decipher.
|
/// KuGou KGM file decipher.
|
||||||
#[wasm_bindgen(js_name=KuGouDecipher)]
|
#[wasm_bindgen(js_name=KuGou)]
|
||||||
pub struct JsKuGouDecipher(Decipher);
|
pub struct JsKuGou(Decipher);
|
||||||
|
|
||||||
#[wasm_bindgen(js_class=KuGouDecipher)]
|
#[wasm_bindgen(js_class = KuGou)]
|
||||||
impl JsKuGouDecipher {
|
impl JsKuGou {
|
||||||
/// Create an instance of cipher (decipher) for decryption
|
/// Parse the KuGou header (0x400 bytes)
|
||||||
#[wasm_bindgen(constructor)]
|
pub fn from_header(header: &[u8]) -> Result<JsKuGou, JsError> {
|
||||||
pub fn new(header: &JsKuGouHeader) -> Result<JsKuGouDecipher, JsError> {
|
let header = Header::from_buffer(header).map_err(JsError::from)?;
|
||||||
Ok(JsKuGouDecipher(
|
let decipher = Decipher::new(&header).map_err(JsError::from)?;
|
||||||
Decipher::new(&header.0).map_err(JsError::from)?,
|
|
||||||
))
|
Ok(JsKuGou(decipher))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypt a buffer.
|
/// Decrypt a buffer.
|
||||||
|
@ -4,3 +4,4 @@ pub mod kgm;
|
|||||||
pub mod kuwo;
|
pub mod kuwo;
|
||||||
pub mod ncm;
|
pub mod ncm;
|
||||||
pub mod qmc;
|
pub mod qmc;
|
||||||
|
pub mod xmly;
|
||||||
|
70
um_wasm/src/exports/xmly.rs
Normal file
70
um_wasm/src/exports/xmly.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use std::convert::TryInto;
|
||||||
|
use umc_xmly::android::{decrypt_android, FileType};
|
||||||
|
use umc_xmly::pc::Header as PCHeader;
|
||||||
|
use umc_xmly::XmlyError;
|
||||||
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
|
use wasm_bindgen::JsError;
|
||||||
|
|
||||||
|
/// Decrypt X2M Header
|
||||||
|
#[wasm_bindgen(js_name=decryptX2MHeader)]
|
||||||
|
pub fn js_decrypt_x2m_header(buffer: &mut [u8]) -> Result<(), JsError> {
|
||||||
|
decrypt_android(FileType::X2M, buffer.try_into().map_err(JsError::from)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrypt X3M Header
|
||||||
|
#[wasm_bindgen(js_name=decryptX3MHeader)]
|
||||||
|
pub fn js_decrypt_x3m_header(buffer: &mut [u8]) -> Result<(), JsError> {
|
||||||
|
decrypt_android(FileType::X3M, buffer.try_into().map_err(JsError::from)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ximalaya PC Decipher.
|
||||||
|
#[wasm_bindgen(js_name=XmlyPC)]
|
||||||
|
pub struct JsXmlyPC(PCHeader);
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_class=XmlyPC)]
|
||||||
|
impl JsXmlyPC {
|
||||||
|
/// Get required bytes for the header, or throw error if not valid XM file.
|
||||||
|
#[wasm_bindgen(js_name = "getHeaderSize")]
|
||||||
|
pub fn get_header_size(buffer: &[u8]) -> Result<usize, JsError> {
|
||||||
|
let required_len = match PCHeader::from_buffer(buffer) {
|
||||||
|
Ok(hdr) => hdr.data_start_offset,
|
||||||
|
Err(XmlyError::MetadataTooSmall(n)) => n,
|
||||||
|
Err(err) => Err(JsError::from(err))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(required_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new XmlyPC decipher
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn new(header: &[u8]) -> Result<JsXmlyPC, JsError> {
|
||||||
|
let hdr = PCHeader::from_buffer(header)?;
|
||||||
|
Ok(Self(hdr))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the first few bytes of the header.
|
||||||
|
#[wasm_bindgen(getter, js_name=audioHeader)]
|
||||||
|
pub fn get_audio_header(&self) -> Vec<u8> {
|
||||||
|
self.0.copy_m4a_header()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the offset where the encrypted header is
|
||||||
|
#[wasm_bindgen(getter, js_name=encryptedHeaderOffset)]
|
||||||
|
pub fn get_encrypted_header_offset(&self) -> usize {
|
||||||
|
self.0.data_start_offset
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the size of encrypted header
|
||||||
|
#[wasm_bindgen(getter, js_name=encryptedHeaderSize)]
|
||||||
|
pub fn get_encrypted_header_len(&self) -> usize {
|
||||||
|
self.0.encrypted_header_size
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrypt encrypted header
|
||||||
|
pub fn decrypt(&self, buffer: &mut [u8]) -> Result<usize, JsError> {
|
||||||
|
let size = self.0.decrypt(buffer)?.len();
|
||||||
|
Ok(size)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user