diff --git a/outdb b/outdb index 09f6c51..12eae6b 100644 Binary files a/outdb and b/outdb differ diff --git a/src/main.rs b/src/main.rs index 12a8087..b196bf3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use std::{fs::File, io::{Read, Write}}; use env_logger::Builder; use log::{error, info, LevelFilter}; use serde::{Deserialize, Serialize}; -use xobjects::{XAlbumItem, XArgument, XDataSet, XDatabase, XPlaylist, XSomeList, XTrackItem}; +use xobjects::{XAlbumItem, XArgument, XDataSet, XDatabase, XLetterJump, XPlArgument, XPlaylist, XPlaylistIndexEntry, XSomeList, XTrackItem}; mod xobjects; @@ -308,7 +308,7 @@ pub fn parse_bytes(data: &[u8]) -> XDatabase { albums.last_mut().unwrap().args.push(XArgument{ arg_type: entry_type, val: g}); }, XSomeList::Playlists(playlists) => { - playlists.last_mut().unwrap().args.push(XArgument{ arg_type: entry_type, val: g}); + playlists.last_mut().unwrap().args.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}); @@ -325,6 +325,12 @@ pub fn parse_bytes(data: &[u8]) -> XDatabase { h += 4; } info!("Indexes: {:?}", v); + match &mut xdb.find_dataset(last_type).child { + XSomeList::Playlists(playlists) => { + playlists.last_mut().unwrap().args.push(XPlArgument::IndexEntry(XPlaylistIndexEntry{data: entry, v})); + } + _ => {} + } }, 53 => { let entry: LetterJumpEntry = bincode::deserialize(&data[i..i+28]).unwrap(); @@ -336,6 +342,12 @@ pub fn parse_bytes(data: &[u8]) -> XDatabase { h += 12; } info!("Indexes: {:?}", v); + match &mut xdb.find_dataset(last_type).child { + XSomeList::Playlists(playlists) => { + playlists.last_mut().unwrap().args.push(XPlArgument::LetterJumpEntry(XLetterJump{ data: entry, v })); + } + _ => {} + } }, 100 => { @@ -431,7 +443,60 @@ fn to_bytes(xdb: XDatabase) -> Vec { let mut pl_bytes = Vec::new(); for u in 0..playlists.len() { let playlist = playlists.get(u).unwrap(); - let mut args = x_args_to_bytes(&playlist.args); + + let mut args: Vec = playlist.args.iter() + .map(|arg| match arg { + XPlArgument::String(xarg) => { + let s = string_to_ipod16(&xarg.val); + let mut b = bincode::serialize(&StringEntry { + entry_type: xarg.arg_type, + unk1: 0, + unk2: 0, + position: 1, + length: s.len() as u32, + unknown: 0, + unk4: 0 + }).unwrap(); + let h = bincode::serialize(&ChunkHeader { + chunk_type: ChunkType::StringTypes.into(), + end_of_chunk: 0x18, + children_count: 16 + 0x18 + s.len() as u32 + }).unwrap(); + b = [h, b, s].concat(); + return b; + }, + XPlArgument::IndexEntry(xpl) => { + let mut b = bincode::serialize(&xpl.data).unwrap(); + let mut v: Vec = Vec::new(); + for i in xpl.v.iter() { + v = [v, i.to_le_bytes().to_vec()].concat(); + } + let h = bincode::serialize(&ChunkHeader { + chunk_type: ChunkType::StringTypes.into(), + end_of_chunk: 60, + children_count: 60 + (4 * xpl.v.len() as u32) + }).unwrap(); + b = [h, b, v].concat(); + return b; + }, + XPlArgument::LetterJumpEntry(xjump) => { + let mut b = bincode::serialize(&xjump.data).unwrap(); + let mut v: Vec = Vec::new(); + for i in xjump.v.iter() { + v.append(&mut bincode::serialize(i).unwrap()); + } + let h = bincode::serialize(&ChunkHeader { + chunk_type: ChunkType::StringTypes.into(), + end_of_chunk: 28, + children_count: 28 + (12 * xjump.v.len() as u32) + }).unwrap(); + b = [h, b, v].concat(); + return b; + }, + }) + .flatten() + .collect(); + pl_bytes.append(&mut generate_header(ChunkType::Playlist, 36,args.len())); pl_bytes.append(&mut bincode::serialize(&playlist.data).unwrap()); pl_bytes.append(&mut args); @@ -492,14 +557,15 @@ fn main() { .filter(None, LevelFilter::Info) .init(); - let mut f = File::open("outdb").unwrap(); // D:\\Documents\\iTunes\\iTunesDB + let mut f = File::open("D:\\Documents\\iTunes\\iTunesDB").unwrap(); // D:\\Documents\\iTunes\\iTunesDB let mut buf = Vec::new(); match f.read_to_end(&mut buf) { Ok(n) => { let data = &buf[..n]; let xdb = parse_bytes(data); - //let mut op = File::create("outdb").unwrap(); - //info!("Write res: {:?}", op.write(&to_bytes(xdb))); + info!("XDB: {:?}", xdb); + let mut op = File::create("outdb").unwrap(); + info!("Write res: {:?}", op.write(&to_bytes(xdb))); }, Err(e) => { error!("Error: {}",e); diff --git a/src/xobjects.rs b/src/xobjects.rs index 6a17bb1..1515ee3 100644 --- a/src/xobjects.rs +++ b/src/xobjects.rs @@ -1,3 +1,5 @@ +use crate::{JumpTable, LetterJumpEntry, PlaylistIndexEntry}; + #[derive(Debug, serde::Serialize)] pub struct XDatabase { @@ -31,7 +33,26 @@ pub struct XAlbumItem { pub struct XPlaylist { pub header: crate::ChunkHeader, pub data: crate::Playlist, - pub args: Vec + pub args: Vec +} + +#[derive(Debug, serde::Serialize)] +pub enum XPlArgument { + String(XArgument), + IndexEntry(XPlaylistIndexEntry), + LetterJumpEntry(XLetterJump) +} + +#[derive(Debug, serde::Serialize)] +pub struct XPlaylistIndexEntry { + pub data: PlaylistIndexEntry, + pub v: Vec +} + +#[derive(Debug, serde::Serialize)] +pub struct XLetterJump { + pub data: LetterJumpEntry, + pub v: Vec } #[derive(Debug, serde::Serialize)]