mc_repack_core/entry/
mod.rs1
2pub mod fs;
4pub mod zip;
6
7use std::sync::Arc;
8use crate::{cfg, errors::ErrorCollector, fop::{FileOp, TypeBlacklist}, ProgressState};
9
10use bytes::Bytes;
11pub use fs::{FSEntryReader, FSEntrySaver};
12pub use zip::{ZipEntryReader, ZipEntrySaver};
13
14pub trait EntryReader {
16 type RE<'a>: ReadEntry where Self: 'a;
18
19 fn read_next(&mut self) -> Option<Self::RE<'_>>;
21
22 fn read_len(&self) -> usize;
24
25 fn read_iter(&mut self) -> ReadEntryIter<Self> where Self: Sized { ReadEntryIter(self) }
27
28 fn read_entries(
30 mut self,
31 mut tx: impl FnMut(NamedEntry) -> crate::Result_<()>,
32 blacklist: &TypeBlacklist
33 ) -> crate::Result_<()> where Self: Sized {
34 for re in self.read_iter() {
35 let Some(ne) = read_entry::<Self>(re, blacklist)? else { continue };
36 tx(ne)?;
37 }
38 Ok(())
39 }
40}
41
42pub fn read_entry<R: EntryReader>(re: R::RE<'_>, blacklist: &TypeBlacklist) -> crate::Result_<Option<NamedEntry>> {
44 let (is_dir, name) = re.meta();
45 let Some(is_dir) = is_dir else { return Ok(None) };
46 let et = if is_dir {
47 NamedEntry::dir(name)
48 } else {
49 let fop = FileOp::by_name(&name, blacklist);
50 if let FileOp::Ignore(_) = fop {
51 return Ok(None);
52 }
53 NamedEntry::file(name, re.data()?, fop)
54 };
55 Ok(Some(et))
56}
57
58#[repr(transparent)]
60pub struct ReadEntryIter<'a, R: EntryReader>(&'a mut R);
61impl <'a, R: EntryReader + 'a> Iterator for ReadEntryIter<'a, R> {
62 type Item = R::RE<'a>;
63
64 #[inline]
65 fn next(&mut self) -> Option<Self::Item> {
66 unsafe { std::mem::transmute(self.0.read_next()) }
68 }
69}
70
71pub trait ReadEntry {
73 fn meta(&self) -> (Option<bool>, Box<str>);
75
76 fn data(self) -> crate::Result_<Bytes>;
78}
79
80pub trait EntrySaver {
82 fn save(&mut self, name: &str, entry: SavingEntry) -> crate::Result_<()>;
84
85 fn save_entries(
88 mut self,
89 rx: impl IntoIterator<Item = NamedEntry>,
90 ev: &mut ErrorCollector,
91 cfgmap: &cfg::ConfigMap,
92 mut ps: impl FnMut(ProgressState) -> crate::Result_<()>,
93 ) -> crate::Result_<()> where Self: Sized {
94 let mut cv = Vec::new();
95 for (n, ne) in rx.into_iter().enumerate() {
96 ps(ProgressState::Push(n, ne.0.clone()))?;
97 if let Some(se) = process_entry(&mut cv, &ne, ev, cfgmap) {
98 self.save(&ne.0, se)?;
99 }
100 }
101 ps(ProgressState::Finish)
102 }
103}
104
105pub fn process_entry<'a>(
107 cbuf: &'a mut Vec<u8>,
108 NamedEntry(name, et): &'a NamedEntry,
109 ev: &mut ErrorCollector,
110 cfgmap: &cfg::ConfigMap,
111) -> Option<SavingEntry<'a>> {
112 let se = match et {
113 EntryType::Directory => SavingEntry::Directory,
114 EntryType::File(buf, fop) => {
115 match fop {
116 FileOp::Ignore(e) => {
117 ev.collect(name.clone(), e.clone().into());
118 return None;
119 }
120 FileOp::Minify(m) => {
121 let buf: &[u8] = match m.minify(cfgmap, buf, cbuf) {
122 Ok(()) => cbuf,
123 Err(e) => {
124 ev.collect(name.clone(), e);
125 buf
126 }
127 };
128 SavingEntry::File(buf, m.compress_min())
129 }
130 FileOp::Recompress(x) => SavingEntry::File(buf, *x as u16),
131 FileOp::Pass => SavingEntry::File(buf, 24)
132 }
133 }
134 };
135 Some(se)
136 }
139
140pub struct NamedEntry(pub Arc<str>, pub EntryType);
142impl NamedEntry {
143 #[inline]
145 pub fn dir(name: impl Into<Arc<str>>) -> Self {
146 Self(name.into(), EntryType::Directory)
147 }
148
149 #[inline]
151 pub fn file(name: impl Into<Arc<str>>, data: impl Into<Bytes>, fop: FileOp) -> Self {
152 Self(name.into(), EntryType::File(data.into(), fop))
153 }
154}
155
156#[derive(Clone)]
158pub enum EntryType {
159 Directory,
161 File(Bytes, FileOp)
163}
164
165pub enum SavingEntry<'a> {
167 Directory,
169 File(&'a [u8], u16)
171}