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 = 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 = 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::(&xdb).unwrap().as_bytes()); //info!("Result: {:?}", r); xdb }