1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use std::io::{self, Read, Seek, SeekFrom, Write};
use byteorder::{ReadBytesExt, LittleEndian};
use flate2::read::ZlibDecoder;
use super::{VirtualXP3, XP3Error, XP3ErrorKind, XP3_MAGIC, archive::XP3Archive, header::{XP3Header, XP3HeaderVersion}, index::file::{IndexSegmentFlag, XP3FileIndexSegment}, index_set::XP3IndexSet};
pub struct XP3Reader;
impl XP3Reader {
pub fn open_archive<T: Read + Seek>(mut stream: T) -> Result<XP3Archive<T>, XP3Error> {
Ok(XP3Archive::new(Self::read_container(&mut stream)?, stream))
}
pub fn read_container<T: Read + Seek>(stream: &mut T) -> Result<VirtualXP3, XP3Error> {
let current = stream.seek(SeekFrom::Current(0))?;
Self::check_archive(stream)?;
let _ = stream.read_u8()?;
let (_, header) = XP3Header::from_bytes(stream)?;
match header.version() {
XP3HeaderVersion::Old => {
}
XP3HeaderVersion::Current { minor_version: _, index_size_offset } => {
stream.seek(SeekFrom::Current(index_size_offset as i64))?;
}
}
let index_offset = stream.read_u64::<LittleEndian>()?;
stream.seek(SeekFrom::Start(current + index_offset))?;
let (_, index_set) = XP3IndexSet::from_bytes(stream)?;
stream.seek(SeekFrom::Start(current))?;
Ok(VirtualXP3::new(header, index_set))
}
pub fn read_segment<O: Read + Seek, T: Write>(segment: &XP3FileIndexSegment, from: &mut O, stream: &mut T) -> Result<(), XP3Error> {
let read_size = segment.saved_size();
let read_offset = segment.data_offset();
let pos = from.seek(SeekFrom::Current(read_offset as i64))?;
match segment.flag() {
IndexSegmentFlag::UnCompressed => {
io::copy(&mut from.take(read_size), stream)?;
},
IndexSegmentFlag::Compressed => {
let decoder = ZlibDecoder::new(from.take(read_size));
io::copy(&mut decoder.take(segment.original_size()), stream)?;
}
}
from.seek(SeekFrom::Start(pos - read_offset))?;
Ok(())
}
pub fn check_archive(stream: &mut impl Read) -> Result<(), XP3Error> {
let mut magic_buffer = [0_u8; 10];
stream.read_exact(&mut magic_buffer)?;
if magic_buffer != XP3_MAGIC {
return Err(XP3Error::new(XP3ErrorKind::InvalidFile, None));
}
Ok(())
}
}