169 lines
7.2 KiB
Rust
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
|
|
} |