modified: Cargo.lock
modified: Cargo.toml modified: src/deserializer.rs modified: src/lib.rs modified: src/objects.rs modified: src/serializer.rs modified: src/xobjects.rs
This commit is contained in:
parent
5a6ca7a9f5
commit
2db99df934
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -90,7 +90,7 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "itunesdb"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"env_logger",
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "itunesdb"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
edition = "2021"
|
||||
authors = ["alterwain"]
|
||||
|
||||
|
@ -38,7 +38,7 @@ pub fn parse_bytes(data: &[u8]) -> XDatabase {
|
||||
let ds: DataSet = bincode::deserialize(&data[i..i+u]).unwrap();
|
||||
info!("DataSet: {:?}", ds);
|
||||
last_type = ds.data_type;
|
||||
xdb.children.push(XDataSet { header: header, data: ds.clone(), child: match ds.data_type {
|
||||
xdb.children.push(XDataSet { header, data: ds, child: match ds.data_type {
|
||||
4 => XSomeList::AlbumList(Vec::new()), // Album List
|
||||
1 => XSomeList::TrackList(Vec::new()), // Track List
|
||||
_ => XSomeList::Playlists(Vec::new()) // Playlist List 3
|
||||
@ -55,7 +55,7 @@ pub fn parse_bytes(data: &[u8]) -> XDatabase {
|
||||
info!("val: {:?}", ai);
|
||||
info!("AlbumItem: {}", u);
|
||||
if let XSomeList::AlbumList(albums) = &mut xdb.find_dataset(4).child {
|
||||
albums.push(XAlbumItem {header: header, data: ai,args: Vec::new()});
|
||||
albums.push(XAlbumItem {header, data: ai,args: Vec::new()});
|
||||
}
|
||||
},
|
||||
ChunkType::TrackList => {
|
||||
@ -68,7 +68,7 @@ pub fn parse_bytes(data: &[u8]) -> XDatabase {
|
||||
let ti: TrackItem = bincode::deserialize(&data[i..i+u]).unwrap();
|
||||
info!("val: {:?}", ti);
|
||||
if let XSomeList::TrackList(tracks) = &mut xdb.find_dataset(1).child {
|
||||
tracks.push(XTrackItem {header: header, data: ti,args: Vec::new()});
|
||||
tracks.push(XTrackItem {header, data: ti,args: Vec::new()});
|
||||
}
|
||||
},
|
||||
ChunkType::SongReference => {
|
||||
@ -123,15 +123,12 @@ pub fn parse_bytes(data: &[u8]) -> XDatabase {
|
||||
h += 4;
|
||||
}
|
||||
//info!("Indexes: {:?}", v);
|
||||
match &mut xdb.find_dataset(last_type).child {
|
||||
XSomeList::Playlists(playlists) => {
|
||||
if playlists.last().unwrap().elems.is_empty() {
|
||||
playlists.last_mut().unwrap().args.push(XPlArgument::IndexEntry(XPlaylistIndexEntry{data: entry, v}));
|
||||
} else {
|
||||
playlists.last_mut().unwrap().elems.last_mut().unwrap().1.push(XPlArgument::IndexEntry(XPlaylistIndexEntry{data: entry, v}));
|
||||
}
|
||||
if let XSomeList::Playlists(playlists) = &mut xdb.find_dataset(last_type).child {
|
||||
if playlists.last().unwrap().elems.is_empty() {
|
||||
playlists.last_mut().unwrap().args.push(XPlArgument::IndexEntry(XPlaylistIndexEntry{data: entry, v}));
|
||||
} else {
|
||||
playlists.last_mut().unwrap().elems.last_mut().unwrap().1.push(XPlArgument::IndexEntry(XPlaylistIndexEntry{data: entry, v}));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
53 => {
|
||||
@ -144,28 +141,22 @@ pub fn parse_bytes(data: &[u8]) -> XDatabase {
|
||||
h += 12;
|
||||
}
|
||||
info!("Indexes: {:?}", v);
|
||||
match &mut xdb.find_dataset(last_type).child {
|
||||
XSomeList::Playlists(playlists) => {
|
||||
if playlists.last().unwrap().elems.is_empty() {
|
||||
playlists.last_mut().unwrap().args.push(XPlArgument::LetterJumpEntry(XLetterJump{ data: entry, v }));
|
||||
} else {
|
||||
playlists.last_mut().unwrap().elems.last_mut().unwrap().1.push(XPlArgument::LetterJumpEntry(XLetterJump{ data: entry, v }));
|
||||
}
|
||||
if let XSomeList::Playlists(playlists) = &mut xdb.find_dataset(last_type).child {
|
||||
if playlists.last().unwrap().elems.is_empty() {
|
||||
playlists.last_mut().unwrap().args.push(XPlArgument::LetterJumpEntry(XLetterJump{ data: entry, v }));
|
||||
} else {
|
||||
playlists.last_mut().unwrap().elems.last_mut().unwrap().1.push(XPlArgument::LetterJumpEntry(XLetterJump{ data: entry, v }));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
100 | 102 | 50 | 51 => {
|
||||
info!("Entry #100,102 fetched");
|
||||
match &mut xdb.find_dataset(last_type).child {
|
||||
XSomeList::Playlists(playlists) => {
|
||||
if playlists.last().unwrap().elems.is_empty() {
|
||||
playlists.last_mut().unwrap().args.push(XPlArgument::RawArgument(data[i-12..i+(header.children_count as usize)-12].to_vec()));
|
||||
} else {
|
||||
playlists.last_mut().unwrap().elems.last_mut().unwrap().1.push(XPlArgument::RawArgument(data[i-12..i+(header.children_count as usize)-12].to_vec()));
|
||||
}
|
||||
if let XSomeList::Playlists(playlists) = &mut xdb.find_dataset(last_type).child {
|
||||
if playlists.last().unwrap().elems.is_empty() {
|
||||
playlists.last_mut().unwrap().args.push(XPlArgument::RawArgument(data[i-12..i+(header.children_count as usize)-12].to_vec()));
|
||||
} else {
|
||||
playlists.last_mut().unwrap().elems.last_mut().unwrap().1.push(XPlArgument::RawArgument(data[i-12..i+(header.children_count as usize)-12].to_vec()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
_ => warn!("Unknown entry: {}", entry_type)
|
||||
@ -181,7 +172,7 @@ pub fn parse_bytes(data: &[u8]) -> XDatabase {
|
||||
let playlist: Playlist = bincode::deserialize(&data[i..i+u]).unwrap();
|
||||
info!("playlist: {:?}", playlist);
|
||||
if let XSomeList::Playlists(playlists) = &mut xdb.find_dataset(last_type).child { // 3
|
||||
playlists.push(XPlaylist {header: header, data: playlist,args: Vec::new(), elems: Vec::new()});
|
||||
playlists.push(XPlaylist {header, data: playlist,args: Vec::new(), elems: Vec::new()});
|
||||
}
|
||||
},
|
||||
_ => { u = 1; info!("Unknown stuff happened"); }
|
||||
|
@ -1,8 +1,3 @@
|
||||
use std::{fs::File, io::{Read, Write}};
|
||||
use env_logger::Builder;
|
||||
use log::{error, info, LevelFilter};
|
||||
use rand::Rng;
|
||||
use xobjects::{XArgument, XPlArgument, XSomeList};
|
||||
|
||||
pub mod objects;
|
||||
pub mod xobjects;
|
||||
|
@ -11,7 +11,7 @@ pub enum ChunkType {
|
||||
PlaylistList,
|
||||
Playlist,
|
||||
SongReference,
|
||||
Unknown
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<[u8; 4]> for ChunkType {
|
||||
@ -27,7 +27,7 @@ impl From<[u8; 4]> for ChunkType {
|
||||
[0x6D, 0x68, 0x69, 0x70] => ChunkType::SongReference,
|
||||
[0x6D, 0x68, 0x6C, 0x70] => ChunkType::PlaylistList,
|
||||
[0x6D, 0x68, 0x79, 0x70] => ChunkType::Playlist,
|
||||
_ => ChunkType::Unknown
|
||||
_ => ChunkType::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -45,7 +45,7 @@ impl From<ChunkType> for [u8; 4] {
|
||||
ChunkType::StringTypes => [0x6D, 0x68, 0x6F, 0x64],
|
||||
ChunkType::PlaylistList => [0x6D, 0x68, 0x6C, 0x70],
|
||||
ChunkType::Playlist => [0x6D, 0x68, 0x79, 0x70],
|
||||
ChunkType::Unknown => [0x00, 0x00, 0x00, 0x00]
|
||||
ChunkType::Unknown => [0x00, 0x00, 0x00, 0x00],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,7 +54,7 @@ impl From<ChunkType> for [u8; 4] {
|
||||
pub struct ChunkHeader {
|
||||
pub chunk_type: [u8; 4],
|
||||
pub end_of_chunk: u32,
|
||||
pub children_count: u32
|
||||
pub children_count: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
@ -69,12 +69,12 @@ pub struct Database {
|
||||
hash: [u8; 20],
|
||||
unk: [u8; 30],
|
||||
unk1: [u8; 32],
|
||||
unk2: [u8; 20]
|
||||
unk2: [u8; 20],
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
|
||||
pub struct DataSet {
|
||||
pub data_type: u32
|
||||
pub data_type: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
@ -83,32 +83,32 @@ pub struct AlbumItem {
|
||||
unknown: u16,
|
||||
album_id_for_track: u16,
|
||||
timestamp: u64,
|
||||
unknown1: u32
|
||||
unknown1: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
|
||||
pub struct TrackItem {
|
||||
pub number_of_strings: u32, // number of mhod's count
|
||||
pub number_of_strings: u32, // number of mhod's count
|
||||
pub unique_id: u32,
|
||||
visible: u32,
|
||||
filetype: u32,
|
||||
pub filetype: u32,
|
||||
type1: u8,
|
||||
type2: u8,
|
||||
compilation_flag: u8,
|
||||
stars: u8,
|
||||
last_modified_time: u32,
|
||||
size: u32,
|
||||
length: u32,
|
||||
pub stars: u8,
|
||||
pub last_modified_time: u32,
|
||||
pub size: u32,
|
||||
pub length: u32,
|
||||
track_number: u32,
|
||||
total_tracks: u32,
|
||||
year: u32,
|
||||
bitrate: u32,
|
||||
sample_rate: u32,
|
||||
pub year: u32,
|
||||
pub bitrate: u32,
|
||||
pub sample_rate: u32,
|
||||
volume: u32,
|
||||
start_time: u32,
|
||||
stop_time: u32,
|
||||
soundcheck: u32,
|
||||
play_count: u32,
|
||||
pub play_count: u32,
|
||||
play_count2: u32,
|
||||
last_played_time: u32,
|
||||
disc_number: u32,
|
||||
@ -119,7 +119,7 @@ pub struct TrackItem {
|
||||
pub dbid: u64,
|
||||
checked: u8,
|
||||
application_rating: u8,
|
||||
bpm: u16,
|
||||
pub bpm: u16,
|
||||
artwork_count: u16,
|
||||
unk9: u16,
|
||||
artwork_size: u32,
|
||||
@ -129,9 +129,9 @@ pub struct TrackItem {
|
||||
unk14: u32,
|
||||
unk15: u32,
|
||||
unk16: u32,
|
||||
skip_count: u32,
|
||||
pub skip_count: u32,
|
||||
last_skipped: u32,
|
||||
has_artwork: u8,
|
||||
pub has_artwork: u8,
|
||||
skip_when_shuffling: u8,
|
||||
remember_playback_position: u8,
|
||||
flag4: u8,
|
||||
@ -146,7 +146,7 @@ pub struct TrackItem {
|
||||
unk25: u32,
|
||||
postgap: u32,
|
||||
unk27: u32,
|
||||
media_type: u32,
|
||||
pub media_type: u32,
|
||||
season_number: u32,
|
||||
episode_number: u32,
|
||||
unk31: [u8; 28],
|
||||
@ -164,22 +164,24 @@ pub struct TrackItem {
|
||||
unk3: [u8; 32],
|
||||
unk4: [u8; 32],
|
||||
unk5: [u8; 32],
|
||||
unk6: [u8; 32]
|
||||
unk6: [u8; 32],
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
pub struct StringEntry { // mhod
|
||||
pub struct StringEntry {
|
||||
// mhod
|
||||
pub entry_type: u32,
|
||||
pub unk1: u32,
|
||||
pub unk2: u32,
|
||||
pub position: u32,
|
||||
pub length: u32,
|
||||
pub unknown: u32,
|
||||
pub unk4: u32
|
||||
pub unk4: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct PlaylistIndexEntry { // mhod
|
||||
pub struct PlaylistIndexEntry {
|
||||
// mhod
|
||||
entry_type: u32,
|
||||
unk1: u32,
|
||||
unk2: u32,
|
||||
@ -189,7 +191,7 @@ pub struct PlaylistIndexEntry { // mhod
|
||||
null_padding1: u64,
|
||||
null_padding2: u64,
|
||||
null_padding3: u64,
|
||||
null_padding4: u64
|
||||
null_padding4: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||
@ -199,14 +201,14 @@ pub struct LetterJumpEntry {
|
||||
unk2: u32,
|
||||
index_type: u32,
|
||||
pub count: u32,
|
||||
null_padding: u64
|
||||
null_padding: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct JumpTable {
|
||||
letter: u32, // UTF-16 LE Uppercase with two padding null bytes
|
||||
entry_num: u32, // the number of the first entry in the corresponding MHOD52 index starting with this letter. Zero-based and incremented by one for each entry, not 4.
|
||||
count: u32 // the count of entries starting with this letter in the corresponding MHOD52.
|
||||
letter: u32, // UTF-16 LE Uppercase with two padding null bytes
|
||||
entry_num: u32, // the number of the first entry in the corresponding MHOD52 index starting with this letter. Zero-based and incremented by one for each entry, not 4.
|
||||
count: u32, // the count of entries starting with this letter in the corresponding MHOD52.
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
@ -235,5 +237,5 @@ pub struct PlaylistItem {
|
||||
timestamp: u32,
|
||||
podcast_grouping_reference: u32,
|
||||
unk: [u8; 30],
|
||||
unk1: [u8; 10]
|
||||
}
|
||||
unk1: [u8; 10],
|
||||
}
|
||||
|
@ -1,17 +1,15 @@
|
||||
use log::info;
|
||||
|
||||
use crate::{objects::{ChunkHeader, ChunkType, PlaylistItem, StringEntry}, xobjects::{XArgument, XDatabase, XLetterJump, XPlArgument, XPlaylistIndexEntry, XSomeList}};
|
||||
use crate::{objects::{ChunkHeader, ChunkType, StringEntry}, xobjects::{XArgument, XDatabase, XLetterJump, XPlArgument, XPlaylistIndexEntry, XSomeList}};
|
||||
|
||||
|
||||
fn string_to_ipod16(str: &str) -> Vec<u8> {
|
||||
str.encode_utf16().map(|f| [f as u8, (f >> 8) as u8]).flatten().collect()
|
||||
str.encode_utf16().flat_map(|f| [f as u8, (f >> 8) as u8]).collect()
|
||||
}
|
||||
|
||||
fn x_args_to_bytes(args: &Vec<XArgument>) -> Vec<u8> {
|
||||
args.iter()
|
||||
.filter(|arg| arg.arg_type <= 15)
|
||||
.map(serialize_string_arg)
|
||||
.flatten()
|
||||
.flat_map(serialize_string_arg)
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -46,7 +44,7 @@ fn serialize_string_arg(xarg: &XArgument) -> Vec<u8> {
|
||||
children_count: 16 + 0x18 + s.len() as u32
|
||||
}).unwrap();
|
||||
b = [h, b, s].concat();
|
||||
return b;
|
||||
b
|
||||
}
|
||||
|
||||
fn serialize_index_entry(xpl: &XPlaylistIndexEntry) -> Vec<u8> {
|
||||
@ -61,7 +59,7 @@ fn serialize_index_entry(xpl: &XPlaylistIndexEntry) -> Vec<u8> {
|
||||
children_count: 12 + (v.len() + b.len()) as u32
|
||||
}).unwrap();
|
||||
b = [h, b, v].concat();
|
||||
return b;
|
||||
b
|
||||
}
|
||||
|
||||
fn serialize_x_letter(xjump: &XLetterJump) -> Vec<u8> {
|
||||
@ -76,18 +74,17 @@ fn serialize_x_letter(xjump: &XLetterJump) -> Vec<u8> {
|
||||
children_count: 12 + (v.len() + b.len()) as u32
|
||||
}).unwrap();
|
||||
b = [h, b, v].concat();
|
||||
return b;
|
||||
b
|
||||
}
|
||||
|
||||
fn serialize_arguments(pl: &Vec<XPlArgument>) -> Vec<u8> {
|
||||
pl.iter()
|
||||
.map(|arg| match arg {
|
||||
.flat_map(|arg| match arg {
|
||||
XPlArgument::String(xarg) => serialize_string_arg(xarg),
|
||||
XPlArgument::IndexEntry(xpl) => serialize_index_entry(xpl),
|
||||
XPlArgument::LetterJumpEntry(xjump) => serialize_x_letter(xjump),
|
||||
XPlArgument::RawArgument(raw_arg) => raw_arg.to_vec()
|
||||
})
|
||||
.flatten()
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ impl XDatabase {
|
||||
fn add_track_to_playlists(&mut self, n: u32, track: &XTrackItem) {
|
||||
if let XSomeList::Playlists(playlists) = &mut self.find_dataset(n).child {
|
||||
let playlist = playlists.last_mut().unwrap();
|
||||
playlist.data.playlist_item_count = playlist.data.playlist_item_count + 1;
|
||||
playlist.data.playlist_item_count += 1;
|
||||
|
||||
let elem = playlist.elems.last().unwrap();
|
||||
let mut pl_item = elem.0.clone();
|
||||
|
Loading…
x
Reference in New Issue
Block a user