use flate2::read::ZlibDecoder;
use flate2::write::ZlibEncoder;
use flate2::Compression;
use std::io::{Read, Write};
use crate::error::{FossilError, Result};
use crate::repo::Database;
use super::delta::apply_delta;
pub fn decompress(data: &[u8]) -> Result<Vec<u8>> {
if data.is_empty() {
return Ok(Vec::new());
}
if data[0] == 0x78 {
let mut decoder = ZlibDecoder::new(data);
let mut decompressed = Vec::new();
decoder
.read_to_end(&mut decompressed)
.map_err(|e| FossilError::Decompression(e.to_string()))?;
return Ok(decompressed);
}
if data.len() > 4 {
if data[4] == 0x78 {
let expected_size = u32::from_be_bytes([data[0], data[1], data[2], data[3]]) as usize;
let mut decoder = ZlibDecoder::new(&data[4..]);
let mut decompressed = Vec::with_capacity(expected_size);
decoder
.read_to_end(&mut decompressed)
.map_err(|e| FossilError::Decompression(e.to_string()))?;
return Ok(decompressed);
}
}
Ok(data.to_vec())
}
pub fn get_artifact_content(db: &Database, rid: i64) -> Result<Vec<u8>> {
let compressed = db.get_blob_by_rid(rid)?;
let decompressed = decompress(&compressed)?;
if let Some(src_rid) = db.get_delta_source(rid)? {
let source = get_artifact_content(db, src_rid)?;
apply_delta(&source, &decompressed)
} else {
Ok(decompressed)
}
}
pub fn get_artifact_by_hash(db: &Database, hash: &str) -> Result<Vec<u8>> {
let rid = db.get_rid_by_hash(hash)?;
get_artifact_content(db, rid)
}
pub fn compress(data: &[u8]) -> Result<Vec<u8>> {
if data.is_empty() {
return Ok(Vec::new());
}
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
encoder
.write_all(data)
.map_err(|e| FossilError::Decompression(e.to_string()))?;
let compressed = encoder
.finish()
.map_err(|e| FossilError::Decompression(e.to_string()))?;
let size = data.len() as u32;
let mut result = Vec::with_capacity(4 + compressed.len());
result.extend_from_slice(&size.to_be_bytes());
result.extend_from_slice(&compressed);
Ok(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_decompress_uncompressed() {
let data = b"hello world";
let result = decompress(data).unwrap();
assert_eq!(result, data);
}
#[test]
fn test_decompress_zlib() {
let compressed = [
0x78, 0x9c, 0xcb, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x06, 0x2c, 0x02, 0x15,
];
let result = decompress(&compressed).unwrap();
assert_eq!(result, b"hello");
}
#[test]
fn test_decompress_with_size_prefix() {
let compressed = [
0x00, 0x00, 0x00, 0x05, 0x78, 0x9c, 0xcb, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x06, 0x2c, 0x02, 0x15,
];
let result = decompress(&compressed).unwrap();
assert_eq!(result, b"hello");
}
}