ITunesDB/src/serializer.rs

169 lines
7.2 KiB
Rust

use crate::{objects::{ChunkHeader, ChunkType, StringEntry}, xobjects::{XArgument, XDatabase, XLetterJump, XPlArgument, XPlaylistIndexEntry, XSomeList}};
fn string_to_ipod16(str: &str) -> Vec<u8> {
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)
.flat_map(serialize_string_arg)
.collect()
}
fn generate_header(ct: ChunkType, header_size: usize, data_len: usize) -> Vec<u8> {
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<u8> {
let mut v: Vec<u8> = Vec::new();
for i in 0..cnt-12 {
v.push(0x00);
}
v
}
fn serialize_string_arg(xarg: &XArgument) -> Vec<u8> {
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<u8> {
let mut b = bincode::serialize(&xpl.data).unwrap();
let mut v: Vec<u8> = 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<u8> {
let mut b = bincode::serialize(&xjump.data).unwrap();
let mut v: Vec<u8> = 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<XPlArgument>) -> Vec<u8> {
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<u8> {
let mut bytes: Vec<u8> = 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<u8> = 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
}