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_ncm",
|
||||
"umc_qmc",
|
||||
"umc_xmly",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
|
@ -44,9 +44,8 @@ impl ArgsXimalaya {
|
||||
_ => bail!("ext not found"),
|
||||
},
|
||||
};
|
||||
let mut read_stream = BufReader::with_capacity(cli.buffer_size, File::open(&self.input)?);
|
||||
let mut write_stream =
|
||||
BufWriter::with_capacity(cli.buffer_size, File::create(&self.output)?);
|
||||
let mut reader = BufReader::with_capacity(cli.buffer_size, File::open(&self.input)?);
|
||||
let mut writer = BufWriter::with_capacity(cli.buffer_size, File::create(&self.output)?);
|
||||
|
||||
match file_type {
|
||||
XimalayaType::X2M | XimalayaType::X3M => {
|
||||
@ -56,36 +55,36 @@ impl ArgsXimalaya {
|
||||
_ => bail!("this should not happen"),
|
||||
};
|
||||
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);
|
||||
write_stream.write_all(&header)?;
|
||||
io::copy(&mut read_stream, &mut write_stream)?;
|
||||
writer.write_all(&header)?;
|
||||
io::copy(&mut reader, &mut writer)?;
|
||||
}
|
||||
XimalayaType::XM => {
|
||||
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) {
|
||||
Ok(hdr) => hdr,
|
||||
Err(umc_xmly::XmlyError::MetadataTooSmall(n)) => {
|
||||
let old_size = header.len();
|
||||
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)?
|
||||
}
|
||||
Err(err) => bail!("failed to parse file: {err}"),
|
||||
};
|
||||
|
||||
// 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
|
||||
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];
|
||||
read_stream.read_exact(&mut header[..])?;
|
||||
write_stream.write_all(xm_file.decrypt(&mut header[..])?)?;
|
||||
reader.read_exact(&mut header[..])?;
|
||||
writer.write_all(xm_file.decrypt(&mut header[..])?)?;
|
||||
|
||||
// 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_ncm = { path = "../um_crypto/ncm" }
|
||||
umc_qmc = { path = "../um_crypto/qmc" }
|
||||
umc_xmly = { path = "../um_crypto/xmly" }
|
||||
um_audio = { path = "../um_audio" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -2,32 +2,18 @@ use umc_kgm::{header::Header, Decipher};
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
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.
|
||||
#[wasm_bindgen(js_name=KuGouDecipher)]
|
||||
pub struct JsKuGouDecipher(Decipher);
|
||||
#[wasm_bindgen(js_name=KuGou)]
|
||||
pub struct JsKuGou(Decipher);
|
||||
|
||||
#[wasm_bindgen(js_class=KuGouDecipher)]
|
||||
impl JsKuGouDecipher {
|
||||
/// Create an instance of cipher (decipher) for decryption
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(header: &JsKuGouHeader) -> Result<JsKuGouDecipher, JsError> {
|
||||
Ok(JsKuGouDecipher(
|
||||
Decipher::new(&header.0).map_err(JsError::from)?,
|
||||
))
|
||||
#[wasm_bindgen(js_class = KuGou)]
|
||||
impl JsKuGou {
|
||||
/// Parse the KuGou header (0x400 bytes)
|
||||
pub fn from_header(header: &[u8]) -> Result<JsKuGou, JsError> {
|
||||
let header = Header::from_buffer(header).map_err(JsError::from)?;
|
||||
let decipher = Decipher::new(&header).map_err(JsError::from)?;
|
||||
|
||||
Ok(JsKuGou(decipher))
|
||||
}
|
||||
|
||||
/// Decrypt a buffer.
|
||||
|
@ -4,3 +4,4 @@ pub mod kgm;
|
||||
pub mod kuwo;
|
||||
pub mod ncm;
|
||||
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