131 lines
4.1 KiB
Rust
131 lines
4.1 KiB
Rust
use crate::deflate::deflate;
|
|
|
|
pub struct Entry {
|
|
pub name: String,
|
|
stored: Vec<u8>,
|
|
uncompressed_size: u32,
|
|
method: u16,
|
|
offset: u32,
|
|
crc: u32,
|
|
}
|
|
|
|
pub struct Zip {
|
|
entries: Vec<Entry>,
|
|
}
|
|
|
|
impl Zip {
|
|
pub fn new() -> Self {
|
|
Zip { entries: Vec::new() }
|
|
}
|
|
|
|
pub fn add(&mut self, name: &str, data: Vec<u8>) {
|
|
let crc = crc32(&data);
|
|
let size = data.len() as u32;
|
|
self.entries.push(Entry {
|
|
name: name.to_string(),
|
|
stored: data,
|
|
uncompressed_size: size,
|
|
method: 0,
|
|
offset: 0,
|
|
crc,
|
|
});
|
|
}
|
|
|
|
pub fn add_deflated(&mut self, name: &str, data: Vec<u8>) {
|
|
let crc = crc32(&data);
|
|
let uncompressed_size = data.len() as u32;
|
|
let compressed = deflate(&data);
|
|
if compressed.len() < data.len() {
|
|
self.entries.push(Entry {
|
|
name: name.to_string(),
|
|
stored: compressed,
|
|
uncompressed_size,
|
|
method: 8,
|
|
offset: 0,
|
|
crc,
|
|
});
|
|
} else {
|
|
self.add(name, data);
|
|
}
|
|
}
|
|
|
|
pub fn finish(mut self) -> Vec<u8> {
|
|
let mut out = Vec::new();
|
|
|
|
for e in self.entries.iter_mut() {
|
|
e.offset = out.len() as u32;
|
|
write_local_header(&mut out, e);
|
|
out.extend_from_slice(&e.stored);
|
|
}
|
|
|
|
let cd_start = out.len() as u32;
|
|
for e in &self.entries {
|
|
write_central_header(&mut out, e);
|
|
}
|
|
let cd_size = out.len() as u32 - cd_start;
|
|
|
|
write_eocd(&mut out, self.entries.len() as u16, cd_size, cd_start);
|
|
|
|
out
|
|
}
|
|
}
|
|
|
|
fn write_local_header(out: &mut Vec<u8>, e: &Entry) {
|
|
out.extend_from_slice(&0x0403_4b50u32.to_le_bytes());
|
|
out.extend_from_slice(&20u16.to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(&e.method.to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(&0x21u16.to_le_bytes());
|
|
out.extend_from_slice(&e.crc.to_le_bytes());
|
|
out.extend_from_slice(&(e.stored.len() as u32).to_le_bytes());
|
|
out.extend_from_slice(&e.uncompressed_size.to_le_bytes());
|
|
out.extend_from_slice(&(e.name.len() as u16).to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(e.name.as_bytes());
|
|
}
|
|
|
|
fn write_central_header(out: &mut Vec<u8>, e: &Entry) {
|
|
out.extend_from_slice(&0x0201_4b50u32.to_le_bytes());
|
|
out.extend_from_slice(&20u16.to_le_bytes());
|
|
out.extend_from_slice(&20u16.to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(&e.method.to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(&0x21u16.to_le_bytes());
|
|
out.extend_from_slice(&e.crc.to_le_bytes());
|
|
out.extend_from_slice(&(e.stored.len() as u32).to_le_bytes());
|
|
out.extend_from_slice(&e.uncompressed_size.to_le_bytes());
|
|
out.extend_from_slice(&(e.name.len() as u16).to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(&0u32.to_le_bytes());
|
|
out.extend_from_slice(&e.offset.to_le_bytes());
|
|
out.extend_from_slice(e.name.as_bytes());
|
|
}
|
|
|
|
fn write_eocd(out: &mut Vec<u8>, count: u16, cd_size: u32, cd_offset: u32) {
|
|
out.extend_from_slice(&0x0605_4b50u32.to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
out.extend_from_slice(&count.to_le_bytes());
|
|
out.extend_from_slice(&count.to_le_bytes());
|
|
out.extend_from_slice(&cd_size.to_le_bytes());
|
|
out.extend_from_slice(&cd_offset.to_le_bytes());
|
|
out.extend_from_slice(&0u16.to_le_bytes());
|
|
}
|
|
|
|
pub fn crc32(data: &[u8]) -> u32 {
|
|
let mut crc: u32 = 0xFFFF_FFFF;
|
|
for &b in data {
|
|
crc ^= b as u32;
|
|
for _ in 0..8 {
|
|
let mask = (crc & 1).wrapping_neg();
|
|
crc = (crc >> 1) ^ (0xEDB8_8320 & mask);
|
|
}
|
|
}
|
|
!crc
|
|
}
|