1use std::{cell::RefCell, collections::hash_map::Iter, io::{self, Cursor, Read, Seek, Write}, marker::PhantomData};
8
9use super::{VirtualXP3, XP3Error, XP3ErrorKind, index::file::XP3FileIndex, reader::XP3Reader};
10
11#[derive(Debug)]
14pub struct XP3Archive<T: Read + Seek> {
15
16 container: VirtualXP3,
17
18 stream: RefCell<T>
19
20}
21
22impl<T: Read + Seek> XP3Archive<T> {
23
24 pub fn new(container: VirtualXP3, data: T) -> Self {
25 Self {
26 container,
27 stream: RefCell::new(data)
28 }
29 }
30
31 pub fn container(&self) -> &VirtualXP3 {
32 &self.container
33 }
34
35 pub fn entries(&self) -> Iter<String, XP3FileIndex> {
36 self.container.index_set().entries()
37 }
38
39 pub fn unpack(&self, name: &String, stream: &mut impl Write) -> Result<(), XP3Error> {
41 let item = self.container.index_set().get(name);
42
43 match item {
44 Some(index) => {
45 for segment in index.segments().iter() {
46 XP3Reader::read_segment(segment, self.stream.borrow_mut().by_ref(), stream)?;
47 }
48
49 Ok(())
50 },
51
52 None => Err(XP3Error::new(XP3ErrorKind::FileNotFound, None))
53 }
54 }
55
56 pub fn close(self) -> (VirtualXP3, T) {
58 (self.container, self.stream.into_inner())
59 }
60
61}
62
63pub trait XP3FilterMethod {
65
66 fn filter(buffer: &[u8], hash: u32, out: &mut impl Write) -> io::Result<usize>;
68
69}
70
71pub struct XP3ArchiveFilter<T, F: XP3FilterMethod> {
73
74 stream: T,
75 hash: u32,
76
77 phantom_method: PhantomData<F>
78
79}
80
81impl<T, F: XP3FilterMethod> XP3ArchiveFilter<T, F> {
82
83 pub fn new(stream: T, hash: u32) -> Self {
84 Self {
85 stream, hash,
86 phantom_method: PhantomData
87 }
88 }
89
90 pub fn into_inner(self) -> T {
92 self.stream
93 }
94
95}
96
97impl<T: Write, F: XP3FilterMethod> Write for XP3ArchiveFilter<T, F> {
98
99 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
100 F::filter(buf, self.hash, &mut self.stream)
101 }
102
103 fn flush(&mut self) -> io::Result<()> {
104 self.stream.flush()
105 }
106
107}
108
109impl<T: Read, F: XP3FilterMethod> Read for XP3ArchiveFilter<T, F> {
110
111 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
112 let mut raw_buf = vec![0_u8; buf.len()];
113
114 self.stream.read(&mut raw_buf)?;
115
116 F::filter(&raw_buf, self.hash, &mut Cursor::new(buf))
117 }
118
119}