refactor: bufreaders and zlib
All checks were successful
CI checks / Clippy (push) Successful in 27s
CI checks / Format (push) Successful in 39s

This commit is contained in:
Patrick MARIE 2025-02-08 16:49:00 +01:00
parent 2a4a411341
commit 6cd2907f0d
Signed by: mycroft
GPG Key ID: BB519E5CD8E7BFA7

View File

@ -5,6 +5,7 @@ use std::{
use anyhow::Error; use anyhow::Error;
use flate2::read::ZlibDecoder; use flate2::read::ZlibDecoder;
use sha1::{Digest, Sha1};
use crate::repository::Repository; use crate::repository::Repository;
@ -22,6 +23,8 @@ struct PackObject {
object_type: PackObjectType, object_type: PackObjectType,
object_size: u32, object_size: u32,
object_data: Vec<u8>, object_data: Vec<u8>,
pos: u64,
end_pos: u64,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@ -109,10 +112,7 @@ where
Ok(val) Ok(val)
} }
fn read_vli_be<R>(file: &mut BufReader<R>, offset: bool) -> Result<u32, Error> fn read_vli_be(file: &mut File, offset: bool) -> Result<u32, Error> {
where
R: Read,
{
let mut val: u32 = 0; let mut val: u32 = 0;
loop { loop {
let mut byte = [0; 1]; let mut byte = [0; 1];
@ -132,18 +132,25 @@ where
Ok(val) Ok(val)
} }
fn decompress_file(file: &mut File) -> Result<Vec<u8>, Error> {
let mut object_data = Vec::new();
let pos = file.stream_position()?;
let mut zlib_decoder = ZlibDecoder::new(&mut *file);
zlib_decoder.read_to_end(&mut object_data)?;
let read_bytes = zlib_decoder.total_in();
file.seek(std::io::SeekFrom::Start(pos + read_bytes))?;
Ok(object_data)
}
fn make_delta_obj( fn make_delta_obj(
file: &mut File, file: &mut File,
base_obj: PackObject, base_obj: PackObject,
object_size: u32, object_size: u32,
) -> Result<PackObject, Error> { ) -> Result<PackObject, Error> {
let mut object_data = Vec::new(); let current_pos = file.stream_position()?;
let object_data = decompress_file(file)?;
let pos = file.seek(SeekFrom::Current(0))?;
let mut zlib_decoder = ZlibDecoder::new(&mut *file);
zlib_decoder.read_to_end(&mut object_data)?;
let read_bytes = zlib_decoder.total_in();
file.seek(std::io::SeekFrom::Start(pos + read_bytes))?;
assert_eq!(object_data.len(), object_size as usize); assert_eq!(object_data.len(), object_size as usize);
@ -158,7 +165,7 @@ fn make_delta_obj(
// ); // );
let mut obj_data = Vec::new(); let mut obj_data = Vec::new();
while fp2.seek(SeekFrom::Current(0))? < object_data.len() as u64 { while fp2.stream_position()? < object_data.len() as u64 {
let mut byte = [0; 1]; let mut byte = [0; 1];
fp2.read_exact(&mut byte)?; fp2.read_exact(&mut byte)?;
let byt = byte[0]; let byt = byte[0];
@ -170,13 +177,14 @@ fn make_delta_obj(
if byt & 0x80 != 0 { if byt & 0x80 != 0 {
// copy data from base object // copy data from base object
let mut vals = [0; 6]; let mut vals = [0; 6];
for i in 0..6 {
for (i, val) in vals.iter_mut().enumerate() {
let bmask = 1 << i; let bmask = 1 << i;
if byt & bmask != 0 { if byt & bmask != 0 {
fp2.read_exact(&mut byte)?; fp2.read_exact(&mut byte)?;
vals[i] = byte[0]; *val = byte[0];
} else { } else {
vals[i] = 0; *val = 0;
} }
} }
@ -205,6 +213,8 @@ fn make_delta_obj(
object_type: base_obj.object_type, object_type: base_obj.object_type,
object_size: patched_obj_size, object_size: patched_obj_size,
object_data: obj_data, object_data: obj_data,
pos: current_pos,
end_pos: file.stream_position()?,
}) })
} }
@ -215,10 +225,10 @@ fn parse_pack_ofs_delta_object(
) -> Result<PackObject, Error> { ) -> Result<PackObject, Error> {
// println!("pos: 0x{:x}", file.seek(SeekFrom::Current(0))?); // println!("pos: 0x{:x}", file.seek(SeekFrom::Current(0))?);
let mut reader = BufReader::new(&mut *file); // let mut reader = BufReader::new(&mut *file);
let offset = read_vli_be(&mut reader, true)?; let offset = read_vli_be(file, true)?;
let new_position = reader.stream_position()?; // let new_position = reader.stream_position()?;
file.seek(SeekFrom::Start(new_position))?; // file.seek(SeekFrom::Start(new_position))?;
let base_obj_offset = fpos - offset as u64; let base_obj_offset = fpos - offset as u64;
@ -227,11 +237,11 @@ fn parse_pack_ofs_delta_object(
// offset, base_obj_offset // offset, base_obj_offset
// ); // );
let prev_pos = file.seek(SeekFrom::Current(0))?; let prev_pos = file.stream_position()?;
file.seek(SeekFrom::Start(base_obj_offset))?; file.seek(SeekFrom::Start(base_obj_offset))?;
let base_obj = parse_pack_entry(file)?; let base_obj = parse_pack_entry(file)?;
assert!(vec![ assert!([
PackObjectType::Commit, PackObjectType::Commit,
PackObjectType::Tree, PackObjectType::Tree,
PackObjectType::Blob, PackObjectType::Blob,
@ -245,12 +255,12 @@ fn parse_pack_ofs_delta_object(
} }
fn parse_pack_entry(file: &mut File) -> Result<PackObject, Error> { fn parse_pack_entry(file: &mut File) -> Result<PackObject, Error> {
let object_pos = file.seek(SeekFrom::Current(0))?; let object_pos = file.stream_position()?;
let mut byte = [0; 1]; let mut byte = [0; 1];
file.read_exact(&mut byte)?; file.read_exact(&mut byte)?;
let object_type: u8 = (byte[0] & 0x70) >> 4; let object_type: u8 = (byte[0] & 0x70) >> 4;
let mut object_data = Vec::new(); let object_data;
let mut object_size: u32 = (byte[0] & 0x0f) as u32; let mut object_size: u32 = (byte[0] & 0x0f) as u32;
let mut bshift = 4; let mut bshift = 4;
@ -260,27 +270,19 @@ fn parse_pack_entry(file: &mut File) -> Result<PackObject, Error> {
bshift += 7; bshift += 7;
} }
println!( // println!(
"Reading object: fpos=0x{:x}, type:{} size:{}", // "Reading object: fpos=0x{:x}, type:{} size:{}",
object_pos, // object_pos,
PackObjectType::from_u8(object_type)?, // PackObjectType::from_u8(object_type)?,
object_size // object_size
); // );
match PackObjectType::from_u8(object_type)? { match PackObjectType::from_u8(object_type)? {
PackObjectType::Commit PackObjectType::Commit
| PackObjectType::Tree | PackObjectType::Tree
| PackObjectType::Blob | PackObjectType::Blob
| PackObjectType::Tag => { | PackObjectType::Tag => {
// get current file offset object_data = decompress_file(file)?;
let pos = file.seek(SeekFrom::Current(0))?;
let mut zlib_decoder = ZlibDecoder::new(&mut *file);
zlib_decoder.read_to_end(&mut object_data)?;
let read_bytes = zlib_decoder.total_in();
file.seek(std::io::SeekFrom::Start(pos + read_bytes))?;
assert_eq!(object_data.len(), object_size as usize); assert_eq!(object_data.len(), object_size as usize);
} }
PackObjectType::OfsDelta => { PackObjectType::OfsDelta => {
@ -293,6 +295,8 @@ fn parse_pack_entry(file: &mut File) -> Result<PackObject, Error> {
object_type: PackObjectType::from_u8(object_type)?, object_type: PackObjectType::from_u8(object_type)?,
object_size, object_size,
object_data, object_data,
pos: object_pos,
end_pos: file.stream_position()?,
}) })
} }
@ -324,14 +328,20 @@ impl Repository {
println!("{:?}", header); println!("{:?}", header);
for _ in 0..header.num_objects { for _ in 0..header.num_objects {
let _obj = parse_pack_entry(&mut file)?; let obj = parse_pack_entry(&mut file)?;
// println!(
// "Read object: type={}, #bytes={}",
// obj.object_type, obj.object_size
// );
// println!("{:?}", obj);
// println!(); let mut hasher = Sha1::new();
hasher.update(format!("{} {}\0", obj.object_type, obj.object_size).as_bytes());
hasher.update(obj.object_data);
println!(
"{} {} {} {} {}",
hex::encode(hasher.finalize()),
obj.object_type,
obj.object_size,
obj.end_pos - obj.pos,
obj.pos,
);
} }
// At the end of the file, there should be a 20-byte SHA-1 checksum // At the end of the file, there should be a 20-byte SHA-1 checksum