ITunesDB/src/deserializer.rs
alterwain@protonmail.com 2db99df934 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
2025-02-12 06:03:43 +03:00

190 lines
11 KiB
Rust

use log::{info, warn};
use crate::{objects::{AlbumItem, ChunkHeader, ChunkType, DataSet, Database, JumpTable, LetterJumpEntry, Playlist, PlaylistIndexEntry, PlaylistItem, StringEntry, TrackItem}, xobjects::{XAlbumItem, XArgument, XDataSet, XDatabase, XLetterJump, XPlArgument, XPlaylist, XPlaylistIndexEntry, XSomeList, XTrackItem}};
enum ChunkState {
Header,
Data
}
pub fn parse_bytes(data: &[u8]) -> XDatabase {
let mut xdb = XDatabase{data: None, header: None, children: Vec::new()};
let mut state = ChunkState::Header;
let mut chunk_header: Option<ChunkHeader> = None;
let mut last_type: u32 = 0;
let mut i = 0;
while i < data.len() {
state = match state {
ChunkState::Header => {
if i + 12 >= data.len() { break; }
chunk_header = Some(bincode::deserialize(&data[i..i+12]).unwrap());
i += 12;
ChunkState::Data
},
ChunkState::Data => {
let mut u = 0;
let header = chunk_header.unwrap();
match ChunkType::from(header.chunk_type) {
ChunkType::Database => {
info!("Db header: {:?}", header);
u = usize::try_from(header.end_of_chunk).unwrap() - 12;
let db: Database = bincode::deserialize(&data[i..i+u]).unwrap();
info!("val: {:?}", db);
xdb.data = Some(db);
xdb.header = Some(header);
},
ChunkType::DataSet => {
u = usize::try_from(header.end_of_chunk).unwrap() - 12;
let ds: DataSet = bincode::deserialize(&data[i..i+u]).unwrap();
info!("DataSet: {:?}", ds);
last_type = 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
}});
},
ChunkType::AlbumList => {
info!("AlbumList");
u = usize::try_from(header.end_of_chunk).unwrap() - 12;
//last_type = 4;
},
ChunkType::AlbumItem => {
u = usize::try_from(header.end_of_chunk).unwrap() - 12;
let ai: AlbumItem = bincode::deserialize(&data[i..i+u]).unwrap();
info!("val: {:?}", ai);
info!("AlbumItem: {}", u);
if let XSomeList::AlbumList(albums) = &mut xdb.find_dataset(4).child {
albums.push(XAlbumItem {header, data: ai,args: Vec::new()});
}
},
ChunkType::TrackList => {
info!("TrackList");
u = usize::try_from(header.end_of_chunk).unwrap() - 12;
//last_type = 1;
},
ChunkType::TrackItem => {
u = usize::try_from(header.end_of_chunk).unwrap() - 12;
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, data: ti,args: Vec::new()});
}
},
ChunkType::SongReference => {
u = usize::try_from(header.end_of_chunk).unwrap() - 12;
let item: PlaylistItem = bincode::deserialize(&data[i..i+76]).unwrap();
info!("PlaylistItem: {:?}", item);
if let XSomeList::Playlists(playlists) = &mut xdb.find_dataset(last_type).child { // 3
playlists.last_mut().unwrap().elems.push((item, Vec::new()));
}
},
ChunkType::StringTypes => {
u = usize::try_from(header.children_count).unwrap() - 12;
let header_offset: usize = (header.end_of_chunk + 4) as usize;
let entry_type = u32::from_le_bytes(data[i..i+4].try_into().unwrap());
match entry_type {
0..=15 => {
let str_end: usize = (header.children_count - 12) as usize;
let entry: StringEntry = bincode::deserialize(&data[i..i+28]).unwrap();
info!("val: {:?}", &entry);
let mut bytes = Vec::new();
let mut h = i+header_offset;
while h < i+str_end {
bytes.push(u16::from_le_bytes(data[h..h+2].try_into().unwrap()));
h+=2;
}
let g = String::from_utf16(&bytes).unwrap();
info!("str: {}", g);
match &mut xdb.find_dataset(last_type).child {
XSomeList::AlbumList(albums) => {
albums.last_mut().unwrap().args.push(XArgument{ arg_type: entry_type, val: g});
},
XSomeList::Playlists(playlists) => {
if playlists.last().unwrap().elems.is_empty() {
playlists.last_mut().unwrap().args.push(XPlArgument::String(XArgument{ arg_type: entry_type, val: g}));
} else {
playlists.last_mut().unwrap().elems.last_mut().unwrap().1.push(XPlArgument::String(XArgument{ arg_type: entry_type, val: g}));
}
},
XSomeList::TrackList(tracks) => {
tracks.last_mut().unwrap().args.push(XArgument{ arg_type: entry_type, val: g});
}
}
},
52 => {
let entry: PlaylistIndexEntry = bincode::deserialize(&data[i..i+60]).unwrap();
//info!("valPl: {:?}", &entry);
let mut h = i+60;
let mut v = Vec::new();
while h < i+60+((4*entry.count) as usize) {
v.push(u32::from_le_bytes(data[h..h+4].try_into().unwrap()));
h += 4;
}
//info!("Indexes: {:?}", 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 => {
let entry: LetterJumpEntry = bincode::deserialize(&data[i..i+28]).unwrap();
//info!("valJT: {:?}", &entry);
let mut h = i+28;
let mut v: Vec<JumpTable> = Vec::new();
while h < i+28+((12*entry.count) as usize) {
v.push(bincode::deserialize(&data[h..h+12]).unwrap());
h += 12;
}
info!("Indexes: {:?}", 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");
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)
}
},
ChunkType::PlaylistList => {
info!("Playlists count: {}", header.children_count);
u = usize::try_from(header.end_of_chunk).unwrap() - 12;
//last_type = 3;
},
ChunkType::Playlist => {
u = usize::try_from(header.end_of_chunk).unwrap() - 12;
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, data: playlist,args: Vec::new(), elems: Vec::new()});
}
},
_ => { u = 1; info!("Unknown stuff happened"); }
}
i += u;
chunk_header = None;
ChunkState::Header
}
}
}
//let mut f = File::create("output.json").unwrap();
//let r = f.write(serde_json::to_string::<XDatabase>(&xdb).unwrap().as_bytes());
//info!("Result: {:?}", r);
xdb
}