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