1mod error;
2mod util;
3
4use std::io::{self, Read, Seek, SeekFrom, BufRead, Write};
5use std::collections::HashMap;
6use crate::error::ErrorKind;
7use crate::util::as_u32_le;
8
9const MAGIC: &str = "PAKT";
10const VERSION: u32 = 1;
11
12struct FileInfo {
13 offset: u32,
14 size: u32
15}
16
17struct Decoder<'a> {
18 buffer: Box<dyn SeekRead + 'a>,
19 total_files: u32,
20 contents: HashMap<String, FileInfo>
21}
22
23impl<'a> Decoder<'a> {
24 fn from(mut buffer: impl SeekRead + 'a) -> Result<Self, error::ErrorKind> {
25 let mut temp_buffer_4_bytes = [0u8; 4];
26 buffer.read(&mut temp_buffer_4_bytes)?;
27 if temp_buffer_4_bytes != MAGIC.as_bytes() {
28 return Err(ErrorKind::InvalidMagicNumber);
29 }
30 buffer.read(&mut temp_buffer_4_bytes)?;
31 if temp_buffer_4_bytes != VERSION.to_le_bytes() {
32 return Err(ErrorKind::InvalidVersion);
33 }
34 buffer.seek(SeekFrom::Current(20 * 4));
35 buffer.read(&mut temp_buffer_4_bytes)?;
36 let total_files = as_u32_le(&temp_buffer_4_bytes);
37
38 let mut contents = HashMap::new();
39 let mut string_buf = Vec::<u8>::new();
40 for _ in 0..total_files {
41 string_buf.clear();
42 buffer.read(&mut temp_buffer_4_bytes)?; string_buf.resize(as_u32_le(&temp_buffer_4_bytes) as usize, 0);
45 buffer.read(&mut string_buf)?;
46 buffer.read(&mut temp_buffer_4_bytes)?;
48 let offset = as_u32_le(&temp_buffer_4_bytes);
49 buffer.read(&mut temp_buffer_4_bytes)?;
51 let size = as_u32_le(&temp_buffer_4_bytes);
52
53 contents.insert(String::from_utf8(string_buf.clone()).unwrap(), FileInfo {
54 size,
55 offset,
56 });
57 }
58
59 Ok(Self {
60 total_files,
61 contents,
62 buffer: Box::new(buffer)
63 })
64 }
65
66 fn total_files(&self) -> u32 {
67 self.total_files
68 }
69
70 fn extract(&mut self, path: &str, mut write: impl Write) -> Result<(), ErrorKind> {
71 let file_info = &self.contents[path];
72 self.buffer.seek(SeekFrom::Start(file_info.offset as u64));
73 io::copy(&mut self.buffer.as_mut().take(file_info.size as u64), &mut write);
74 Ok(())
75 }
76}
77
78trait SeekRead: Seek + Read {}
79impl<T: Seek + Read> SeekRead for T {}
80
81pub struct BufferInfo {
82 buffer: Box<dyn SeekRead>,
83 size: u32
84}
85
86pub struct Encoder {
87 contents: HashMap<String, BufferInfo>,
88 paths_len: u32
89}
90
91impl Encoder {
92 pub fn new() -> Self {
93 Self {
94 contents: HashMap::new(),
95 paths_len: 0
96 }
97 }
98
99 pub fn add_file(&mut self, path: &str, mut buffer: Box<dyn SeekRead>) {
100 self.paths_len += path.len() as u32;
101 let size = buffer.seek(SeekFrom::End(0)).unwrap() as u32;
102 buffer.seek(SeekFrom::Start(0));
103 self.contents.insert(path.to_owned(), BufferInfo {
104 buffer,
105 size
106 });
107 println!("path {} size {}", path, size);
108 }
109
110 pub fn write(&mut self, mut write_buffer: impl io::Write) {
111 write_buffer.write(MAGIC.as_bytes());
113 write_buffer.write(&VERSION.to_le_bytes());
115 write_buffer.write(&[0u8; 20 * 4]);
117 write_buffer.write(&(self.contents.len() as u32).to_le_bytes());
118
119 let total_files = self.contents.len() as u32;
120 let mut pad = 4 + 4 + 20 * 4 + 4 + self.paths_len + (4 + 4 + 4) * total_files;
121 for (path, buffer_info) in self.contents.iter_mut() {
122 write_buffer.write(&(path.len() as u32).to_le_bytes()); write_buffer.write(path.as_bytes());
125 write_buffer.write(&pad.to_le_bytes());
127 write_buffer.write(&(buffer_info.size).to_le_bytes());
129 pad += buffer_info.size;
130 }
131 for (path, mut read_buffer) in self.contents.iter_mut() {
132 io::copy(&mut read_buffer.buffer, &mut write_buffer);
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 #[test]
140 fn encode() {
141 use super::*;
142 use std::fs::File;
143 use std::io::prelude::*;
144
145 let mut encoder = Encoder::new();
146 encoder.add_file("tempeh.jpg", Box::new(File::open("test/image/tempeh.jpg").unwrap()));
147 encoder.write(File::create("test/output/encode.pakt").unwrap());
148 }
149
150 #[test]
151 fn encode_and_extract() {
152 use super::*;
153 use std::fs::File;
154 use std::io::prelude::*;
155 use file_diff::diff;
156
157 let mut encoder = Encoder::new();
158 encoder.add_file("tempeh.jpg", Box::new(File::open("test/image/tempeh.jpg").unwrap()));
159 encoder.add_file("imperial.ogg", Box::new(File::open("test/music/imperial.ogg").unwrap()));
160 encoder.write(File::create("test/output/encode_and_read.pakt").unwrap());
161
162 let mut decoder = Decoder::from(File::open("test/output/encode_and_read.pakt").unwrap()).unwrap();
163 assert_eq!(decoder.total_files(), 2);
164 decoder.extract("tempeh.jpg", File::create("test/output/tempeh.jpg").unwrap());
165 decoder.extract("imperial.ogg", File::create("test/output/imperial.ogg").unwrap());
166 assert!(diff("test/output/tempeh.jpg", "test/image/tempeh.jpg"));
167 assert!(diff("test/output/imperial.ogg", "test/music/imperial.ogg"));
168 }
169}