extern crate byteorder; extern crate prs_rust; use self::byteorder::{ReadBytesExt, WriteBytesExt, BigEndian, LittleEndian}; use self::prs_rust::prs; use std::str; use std::fs::File; use std::io::{Read, Seek, SeekFrom, Write}; pub struct OneJod { read_handle: R, header: OneJodHead, entries: Vec, } impl OneJod where R: Read + Seek, { pub fn from_archive(mut input: R) -> OneJod { let mut head = OneJodHead { magic: [0; 16], _unknown1: 0, category: [0; 32], file_count: 0, reserved: [0; 128], }; input.read_exact(&mut head.magic); assert_eq!(head.magic(), b"ThisIsOneFile\0\0\0"); head._unknown1 = input.read_u32::().unwrap(); input.read_exact(&mut head.category); head.file_count = input.read_u32::().unwrap(); input.read_exact(&mut head.reserved); let mut entries = Vec::new(); for i in 0..head.file_count() { let mut entry = OneJodEntry { _unknown1: 0, id: 0, size_cmp: 0, _unknown2: 0, size_dec: 0, id_again: 0, offset: 0, file_name: [0; 188], }; entry._unknown1 = input.read_u32::().unwrap(); entry.id = input.read_u32::().unwrap(); entry.size_cmp = input.read_u32::().unwrap(); entry._unknown2 = input.read_u32::().unwrap(); entry.size_dec = input.read_u32::().unwrap(); entry.id_again = input.read_u32::().unwrap(); entry.offset = input.read_u32::().unwrap(); input.read_exact(&mut entry.file_name); assert_eq!(entry.id(), i); entries.push(entry); } OneJod{ read_handle: input, header: head, entries, } } pub fn extract(&mut self) { for entry in &self.entries { let mut cmp_buf = vec![0u8; entry.size_cmp() as usize]; self.read_handle.seek(SeekFrom::Start(entry.offset() as u64)); self.read_handle.read_exact(cmp_buf.as_mut_slice()); let mut dec_buf = prs::decompress::Decompressor::new(&cmp_buf).decompress(); println!("{}", entry.file_name()); let mut file_out = File::create(entry.file_name()).unwrap(); file_out.write_all(&dec_buf); } } } struct OneJodHead { magic: [u8; 16], _unknown1: u32, category: [u8; 32], file_count: u32, reserved: [u8; 128], } impl OneJodHead { fn magic(&self) -> &[u8] { &self.magic } fn magic_mut(&mut self) -> &mut [u8] { &mut self.magic } fn _unknown1(&self) -> u32 { self._unknown1 } fn set_unknown1(&mut self, n: u32) { self._unknown1 = n; } // NB: may not really be utf8? should probably be ascii, though... fn category(&self) -> &str { str::from_utf8(&self.category).unwrap() } fn category_mut(&mut self) -> &mut str { str::from_utf8_mut(&mut self.category).unwrap() } fn set_category(&mut self, n: &str) { self.category.copy_from_slice(n.as_bytes()); } fn file_count(&self) -> u32 { self.file_count } fn set_file_count(&mut self, n: u32) { self.file_count = n; } fn reserved(&self) -> &[u8] { &self.reserved } fn reserved_mut(&mut self) -> &mut [u8] { &mut self.reserved } } struct OneJodEntry { _unknown1: u32, id: u32, size_cmp: u32, _unknown2: u32, size_dec: u32, id_again: u32, offset: u32, file_name: [u8; 188], } impl OneJodEntry { fn _unknown1(&self) -> u32 { self._unknown1 } fn set_unknown1(&mut self, n: u32) { self._unknown1 = n; } fn id(&self) -> u32 { assert_eq!(self.id, self.id_again); self.id } fn set_id(&mut self, n: u32) { self.id = n; self.id_again = n; } fn size_cmp(&self) -> u32 { self.size_cmp } fn set_size_cmp(&mut self, n: u32) { self.size_cmp = n; } fn _unknown2(&self) -> u32 { self._unknown2 } fn set_unknown2(&mut self, n: u32) { self._unknown2 = n; } fn size_dec(&self) -> u32 { self.size_dec } fn set_size_dec(&mut self, n: u32) { self.size_dec = n; } fn offset(&self) -> u32 { self.offset } fn set_offset(&mut self, n: u32) { self.offset = n; } fn file_name(&self) -> &str { let idx = self.file_name.iter().position(|x| *x == 0u8).unwrap(); str::from_utf8(&self.file_name[0..idx]).unwrap() } fn file_name_mut(&mut self) -> &mut str { str::from_utf8_mut(&mut self.file_name).unwrap() } fn set_file_name(&mut self, n: &str) { self.file_name.copy_from_slice(n.as_bytes()); } }