use crate::{objects::{ChunkHeader, ChunkType, StringEntry}, xobjects::{XArgument, XDatabase, XLetterJump, XPlArgument, XPlaylistIndexEntry, XSomeList}}; fn string_to_ipod16(str: &str) -> Vec { str.encode_utf16().flat_map(|f| [f as u8, (f >> 8) as u8]).collect() } fn x_args_to_bytes(args: &Vec) -> Vec { args.iter() .filter(|arg| arg.arg_type <= 15) .flat_map(serialize_string_arg) .collect() } fn generate_header(ct: ChunkType, header_size: usize, data_len: usize) -> Vec { let header_size = 12 + header_size as u32; let header = ChunkHeader{ chunk_type: ct.into(), end_of_chunk: header_size, children_count: header_size + data_len as u32}; bincode::serialize(&header).unwrap() } fn generate_zeroes(cnt: u32) -> Vec { let mut v: Vec = Vec::new(); for i in 0..cnt-12 { v.push(0x00); } v } fn serialize_string_arg(xarg: &XArgument) -> Vec { 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: 1, 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(); b } fn serialize_index_entry(xpl: &XPlaylistIndexEntry) -> Vec { 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: 24, children_count: 12 + (v.len() + b.len()) as u32 }).unwrap(); b = [h, b, v].concat(); b } fn serialize_x_letter(xjump: &XLetterJump) -> Vec { 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: 24, children_count: 12 + (v.len() + b.len()) as u32 }).unwrap(); b = [h, b, v].concat(); b } fn serialize_arguments(pl: &Vec) -> Vec { pl.iter() .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() }) .collect() } pub fn to_bytes(xdb: &mut XDatabase) -> Vec { let mut bytes: Vec = Vec::new(); for i in 0..xdb.children.len() { let data_set = xdb.children.get(i).unwrap(); match &data_set.child { XSomeList::Playlists(playlists) => { let mut pl_bytes = Vec::new(); for u in 0..playlists.len() { let playlist = playlists.get(u).unwrap(); let mut args: Vec = serialize_arguments(&playlist.args); for (playlist_item, xargs) in playlist.elems.iter() { let mut a = serialize_arguments(xargs); args.append(&mut generate_header(ChunkType::SongReference, 64,a.len())); args.append(&mut bincode::serialize(playlist_item).unwrap()); args.append(&mut a); } pl_bytes.append(&mut generate_header(ChunkType::Playlist, 172,args.len())); pl_bytes.append(&mut bincode::serialize(&playlist.data).unwrap()); pl_bytes.append(&mut generate_zeroes(104)); pl_bytes.append(&mut args); } let mhlp = ChunkHeader { chunk_type: ChunkType::PlaylistList.into(), end_of_chunk: 92, children_count: playlists.len() as u32 }; let mut mhlp = bincode::serialize(&mhlp).unwrap(); bytes.append(&mut generate_header(ChunkType::DataSet, 84, mhlp.len() + pl_bytes.len() + 80)); // 728 bytes.append(&mut bincode::serialize(&data_set.data).unwrap()); bytes.append(&mut generate_zeroes(92)); bytes.append(&mut mhlp); bytes.append(&mut generate_zeroes(92)); bytes.append(&mut pl_bytes); }, XSomeList::AlbumList(albums) => { let mut al_bytes = Vec::new(); for u in 0..albums.len() { let album = albums.get(u).unwrap(); let mut args = x_args_to_bytes(&album.args); al_bytes.append(&mut generate_header(ChunkType::AlbumItem, 76,args.len())); al_bytes.append(&mut bincode::serialize(&album.data).unwrap()); al_bytes.append(&mut generate_zeroes(68)); al_bytes.append(&mut args); } let mhla = ChunkHeader { chunk_type: ChunkType::AlbumList.into(), end_of_chunk: 92, children_count: albums.len() as u32 }; let mut mhla = bincode::serialize(&mhla).unwrap(); bytes.append(&mut generate_header(ChunkType::DataSet, 84, mhla.len() + 168)); bytes.append(&mut bincode::serialize(&data_set.data).unwrap()); bytes.append(&mut generate_zeroes(92)); bytes.append(&mut mhla); bytes.append(&mut generate_zeroes(92)); bytes.append(&mut al_bytes); }, XSomeList::TrackList(tracks) => { let mut tr_bytes = Vec::new(); for u in 0..tracks.len() { let track = tracks.get(u).unwrap(); let mut args = x_args_to_bytes(&track.args); tr_bytes.append(&mut generate_header(ChunkType::TrackItem, 612,args.len())); tr_bytes.append(&mut bincode::serialize(&track.data).unwrap()); tr_bytes.append(&mut generate_zeroes(108)); tr_bytes.append(&mut args); } let mhlt = ChunkHeader { chunk_type: ChunkType::TrackList.into(), end_of_chunk: 92, children_count: tracks.len() as u32 }; let mut mhlt = bincode::serialize(&mhlt).unwrap(); bytes.append(&mut generate_header(ChunkType::DataSet, 84, mhlt.len() + tr_bytes.len() + 80)); bytes.append(&mut bincode::serialize(&data_set.data).unwrap()); bytes.append(&mut generate_zeroes(92)); bytes.append(&mut mhlt); bytes.append(&mut generate_zeroes(92)); bytes.append(&mut tr_bytes); } } } let sdb = bincode::serialize(&xdb.data.as_ref().unwrap()).unwrap(); let sdb_len = sdb.len(); let h = xdb.header.unwrap(); bytes = [sdb, generate_zeroes(h.end_of_chunk - sdb_len as u32), bytes].concat(); bytes = [generate_header(ChunkType::Database, (h.end_of_chunk - 12) as usize, bytes.len() - (h.end_of_chunk - 12) as usize), bytes].concat(); bytes }