modified: outdb
modified: src/main.rs modified: src/xobjects.rs
This commit is contained in:
parent
84f5824411
commit
4b07a48a08
78
src/main.rs
78
src/main.rs
@ -2,7 +2,7 @@ use std::{fs::File, io::{Read, Write}};
|
|||||||
use env_logger::Builder;
|
use env_logger::Builder;
|
||||||
use log::{error, info, LevelFilter};
|
use log::{error, info, LevelFilter};
|
||||||
use serde::{Deserialize, Serialize};
|
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;
|
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});
|
albums.last_mut().unwrap().args.push(XArgument{ arg_type: entry_type, val: g});
|
||||||
},
|
},
|
||||||
XSomeList::Playlists(playlists) => {
|
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) => {
|
XSomeList::TrackList(tracks) => {
|
||||||
tracks.last_mut().unwrap().args.push(XArgument{ arg_type: entry_type, val: g});
|
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;
|
h += 4;
|
||||||
}
|
}
|
||||||
info!("Indexes: {:?}", v);
|
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 => {
|
53 => {
|
||||||
let entry: LetterJumpEntry = bincode::deserialize(&data[i..i+28]).unwrap();
|
let entry: LetterJumpEntry = bincode::deserialize(&data[i..i+28]).unwrap();
|
||||||
@ -336,6 +342,12 @@ pub fn parse_bytes(data: &[u8]) -> XDatabase {
|
|||||||
h += 12;
|
h += 12;
|
||||||
}
|
}
|
||||||
info!("Indexes: {:?}", v);
|
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 => {
|
100 => {
|
||||||
|
|
||||||
@ -431,7 +443,60 @@ fn to_bytes(xdb: XDatabase) -> Vec<u8> {
|
|||||||
let mut pl_bytes = Vec::new();
|
let mut pl_bytes = Vec::new();
|
||||||
for u in 0..playlists.len() {
|
for u in 0..playlists.len() {
|
||||||
let playlist = playlists.get(u).unwrap();
|
let playlist = playlists.get(u).unwrap();
|
||||||
let mut args = x_args_to_bytes(&playlist.args);
|
|
||||||
|
let mut args: Vec<u8> = 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<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: 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<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: 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 generate_header(ChunkType::Playlist, 36,args.len()));
|
||||||
pl_bytes.append(&mut bincode::serialize(&playlist.data).unwrap());
|
pl_bytes.append(&mut bincode::serialize(&playlist.data).unwrap());
|
||||||
pl_bytes.append(&mut args);
|
pl_bytes.append(&mut args);
|
||||||
@ -492,14 +557,15 @@ fn main() {
|
|||||||
.filter(None, LevelFilter::Info)
|
.filter(None, LevelFilter::Info)
|
||||||
.init();
|
.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();
|
let mut buf = Vec::new();
|
||||||
match f.read_to_end(&mut buf) {
|
match f.read_to_end(&mut buf) {
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
let data = &buf[..n];
|
let data = &buf[..n];
|
||||||
let xdb = parse_bytes(data);
|
let xdb = parse_bytes(data);
|
||||||
//let mut op = File::create("outdb").unwrap();
|
info!("XDB: {:?}", xdb);
|
||||||
//info!("Write res: {:?}", op.write(&to_bytes(xdb)));
|
let mut op = File::create("outdb").unwrap();
|
||||||
|
info!("Write res: {:?}", op.write(&to_bytes(xdb)));
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error: {}",e);
|
error!("Error: {}",e);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use crate::{JumpTable, LetterJumpEntry, PlaylistIndexEntry};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize)]
|
#[derive(Debug, serde::Serialize)]
|
||||||
pub struct XDatabase {
|
pub struct XDatabase {
|
||||||
@ -31,7 +33,26 @@ pub struct XAlbumItem {
|
|||||||
pub struct XPlaylist {
|
pub struct XPlaylist {
|
||||||
pub header: crate::ChunkHeader,
|
pub header: crate::ChunkHeader,
|
||||||
pub data: crate::Playlist,
|
pub data: crate::Playlist,
|
||||||
pub args: Vec<XArgument>
|
pub args: Vec<XPlArgument>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<u32>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
pub struct XLetterJump {
|
||||||
|
pub data: LetterJumpEntry,
|
||||||
|
pub v: Vec<JumpTable>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize)]
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user