1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::PathBuf;
use flate2::read::ZlibDecoder;
use crate::die;
pub enum GitObjectType {
Blob,
Commit,
Tag,
Tree,
Undefined,
}
struct GitObject {
object_type: GitObjectType,
size: usize,
data: Vec<u8>,
}
impl GitObject {
fn new() -> Self {
Self {
object_type: GitObjectType::Undefined,
size: 0,
data: Vec::new(),
}
}
fn from_file(path: PathBuf) -> Self {
if !path.is_file() {
return Self::new();
}
if let Ok(compressed_content) = File::open(path.clone()) {
let sha = path.file_name().unwrap().to_str().unwrap();
let decoder = ZlibDecoder::new(BufReader::new(compressed_content));
let mut reader = ZlibDecoder::new(decoder);
let mut type_buffer = Vec::new();
let mut size_buffer = Vec::new();
let mut data = Vec::new();
let mut byte = [0u8; 1];
let mut current_segment: u8 = 0; // 0: type, 1: size, 2: content
while reader.read_exact(&mut byte).is_ok() {
match current_segment {
0 => {
if byte[0] != b' ' {
type_buffer.push(byte[0]);
} else {
current_segment += 1;
}
}
1 => {
if byte[0] == b'\x00' {
size_buffer.push(byte[0]);
} else {
current_segment += 1;
}
}
_ => {
data.push(byte[0]);
}
}
}
let object_type = match String::from_utf8_lossy(&type_buffer).to_string().as_str() {
"commit" => { GitObjectType::Commit }
"tree" => { GitObjectType::Tree }
"tag" => { GitObjectType::Tag }
"blob" => { GitObjectType::Blob }
_ => {
die!(
"Unknown object type: {} in object {}",
String::from_utf8_lossy(&type_buffer),
sha
);
}
};
let Ok(size) = String::from_utf8_lossy(&size_buffer).to_string().parse::<usize>() else {
die!("Malformed object {}, unknown size", sha);
};
Self {
object_type,
size,
data,
}
} else {
Self::new()
}
}
}
|