feat: added glue exports for kwm/qmc

This commit is contained in:
鲁树人
2024-09-07 13:13:39 +01:00
parent e7d8231474
commit 3292ad51ea
16 changed files with 398 additions and 241 deletions

View File

@@ -36,6 +36,18 @@ pub enum Cipher {
V2(CipherV2),
}
impl Cipher {
pub fn decrypt<T>(&self, data: &mut T, offset: usize)
where
T: AsMut<[u8]> + ?Sized,
{
match self {
Cipher::V1(cipher) => cipher.decrypt(data, offset),
Cipher::V2(cipher) => cipher.decrypt(data, offset),
}
}
}
pub struct Header {
pub magic: [u8; 0x10],

View File

@@ -7,6 +7,6 @@ edition = "2021"
anyhow = "1.0.86"
byteorder = "1.5.0"
itertools = "0.13.0"
tc_tea = "0.1.4"
tc_tea = { version = "0.1.4", default-features = false, features = [] }
thiserror = "1.0.63"
umc_utils = { path = "../utils" }
umc_utils = { path = "../utils" }

View File

@@ -10,7 +10,7 @@ pub struct QTagMetadata {
}
impl MetadataParser for QTagMetadata {
fn from_byte_slice(buffer: &[u8]) -> anyhow::Result<Option<Metadata>> {
fn from_byte_slice(buffer: &[u8]) -> Result<Option<Metadata>, FooterParseError> {
if buffer.len() < 8 {
Err(FooterParseError::BufferTooSmall(8))?;
}
@@ -39,7 +39,9 @@ impl MetadataParser for QTagMetadata {
ekey: Some(ekey.into()),
size: actual_payload_len + 8,
data: Data::AndroidQTag(QTagMetadata {
resource_id: resource_id.parse()?,
resource_id: resource_id.parse().map_err(|_| {
FooterParseError::StringToIntError(resource_id.to_string())
})?,
}),
}));
}

View File

@@ -6,13 +6,13 @@ use itertools::Itertools;
pub struct STagMetadata {
/// Resource identifier (aka. `file.media_mid`).
pub media_mid: String,
/// Resource id (numeric)
pub resource_id: u64,
}
impl MetadataParser for STagMetadata {
fn from_byte_slice(buffer: &[u8]) -> anyhow::Result<Option<Metadata>> {
fn from_byte_slice(buffer: &[u8]) -> Result<Option<Metadata>, FooterParseError> {
if buffer.len() < 8 {
Err(FooterParseError::BufferTooSmall(8))?;
}
@@ -37,7 +37,9 @@ impl MetadataParser for STagMetadata {
ekey: None,
size: actual_payload_len + 8,
data: Data::AndroidSTag(STagMetadata {
resource_id: id.parse()?,
resource_id: id
.parse()
.map_err(|_| FooterParseError::StringToIntError(id.to_string()))?,
media_mid: media_mid.to_string(),
}),
}));

View File

@@ -9,7 +9,6 @@ use crate::footer::{
android_qtag::QTagMetadata, android_stag::STagMetadata, pc_v1_legacy::PcV1Legacy,
pc_v2_musicex::PcV2MusicEx,
};
use anyhow::Result;
use thiserror::Error;
pub const INITIAL_DETECTION_LEN: usize = 1024;
@@ -27,6 +26,8 @@ pub enum FooterParseError {
PCv2InvalidVersion(u32),
#[error("PCv2/MusicEx: Invalid `MusicEx` size: {0}")]
PCv2MusicExUnsupportedPayloadSize(usize),
#[error("PCv2/MusicEx: Invalid `MusicEx` data: {0}")]
PCv2MusicExInvalidError(anyhow::Error),
#[error("Android/STag: Invalid ID field: {0}")]
STagInvalidId(String),
@@ -41,6 +42,9 @@ pub enum FooterParseError {
QTagInvalidVersion(String),
#[error("Android/QTag: Invalid EKey field: {0}")]
QTagInvalidEKey(String),
#[error("Parse: Failed to parse string '{0}' as integer")]
StringToIntError(String),
}
/// Footer type
@@ -71,10 +75,10 @@ pub struct Metadata {
}
pub trait MetadataParser {
fn from_byte_slice(buffer: &[u8]) -> Result<Option<Metadata>>;
fn from_byte_slice(buffer: &[u8]) -> Result<Option<Metadata>, FooterParseError>;
}
pub fn from_byte_slice(buffer: &[u8]) -> Result<Option<Metadata>> {
pub fn from_byte_slice(buffer: &[u8]) -> Result<Option<Metadata>, FooterParseError> {
if let Some(metadata) = STagMetadata::from_byte_slice(buffer)? {
return Ok(Some(metadata));
}

View File

@@ -1,8 +1,8 @@
use std::io::{Cursor, Read};
use byteorder::{ByteOrder,ReadBytesExt, LE};
use crate::footer::{Data, FooterParseError, Metadata};
use crate::footer::pc_v2_musicex::PcV2MusicEx;
use crate::footer::utils::from_ascii_utf16;
use crate::footer::{Data, FooterParseError, Metadata};
use byteorder::{ByteOrder, ReadBytesExt, LE};
use std::io::{Cursor, Read};
#[derive(Debug, Clone, PartialEq)]
pub struct MusicExV1 {
@@ -52,7 +52,7 @@ impl MusicExV1 {
}
}
pub fn parse_v1(footer: &[u8]) -> anyhow::Result<Option<Metadata>> {
pub fn parse_v1(footer: &[u8]) -> Result<Option<Metadata>, FooterParseError> {
let (payload, payload_len) = footer.split_at(footer.len() - 4);
let payload_len = LE::read_u32(&payload_len) as usize;
if payload_len != 0xC0 {
@@ -60,9 +60,10 @@ pub fn parse_v1(footer: &[u8]) -> anyhow::Result<Option<Metadata>> {
payload_len,
))?;
}
let payload = &payload[payload.len() - (payload_len - 0x10)..];
let payload = MusicExV1::from_bytes(payload)?;
let payload =
MusicExV1::from_bytes(payload).map_err(FooterParseError::PCv2MusicExInvalidError)?;
let mid = from_ascii_utf16(&payload.mid);
let media_filename = from_ascii_utf16(&payload.media_filename);

View File

@@ -8,7 +8,7 @@ pub const MAX_ALLOWED_EKEY_LEN: usize = 0x500;
pub struct PcV1Legacy;
impl MetadataParser for PcV1Legacy {
fn from_byte_slice(buffer: &[u8]) -> anyhow::Result<Option<Metadata>> {
fn from_byte_slice(buffer: &[u8]) -> Result<Option<Metadata>, FooterParseError> {
if buffer.len() < 8 {
Err(FooterParseError::BufferTooSmall(8))?;
}

View File

@@ -1,5 +1,4 @@
use crate::footer::{musicex_v1, FooterParseError, Metadata, MetadataParser};
use anyhow::Result;
use byteorder::{ByteOrder, LE};
#[derive(Debug, Clone, PartialEq)]
@@ -12,7 +11,7 @@ pub struct PcV2MusicEx {
}
impl MetadataParser for PcV2MusicEx {
fn from_byte_slice(payload: &[u8]) -> Result<Option<Metadata>> {
fn from_byte_slice(payload: &[u8]) -> Result<Option<Metadata>, FooterParseError> {
if payload.len() < 16 {
Err(FooterParseError::BufferTooSmall(16))?;
}