summaryrefslogtreecommitdiff
path: root/src/object.rs
blob: 5824c47adc47ba773c6c46f29d00fe07c11d8ce7 (plain)
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()
        }
    }
}