git_pack/data/entry/
decode.rs1use std::io;
2
3use git_features::decode::{leb64, leb64_from_read};
4
5use super::{BLOB, COMMIT, OFS_DELTA, REF_DELTA, TAG, TREE};
6use crate::data;
7
8impl data::Entry {
10 pub fn from_bytes(d: &[u8], pack_offset: data::Offset, hash_len: usize) -> data::Entry {
16 let (type_id, size, mut consumed) = parse_header_info(d);
17
18 use crate::data::entry::Header::*;
19 let object = match type_id {
20 OFS_DELTA => {
21 let (distance, leb_bytes) = leb64(&d[consumed..]);
22 let delta = OfsDelta {
23 base_distance: distance,
24 };
25 consumed += leb_bytes;
26 delta
27 }
28 REF_DELTA => {
29 let delta = RefDelta {
30 base_id: git_hash::ObjectId::from(&d[consumed..][..hash_len]),
31 };
32 consumed += hash_len;
33 delta
34 }
35 BLOB => Blob,
36 TREE => Tree,
37 COMMIT => Commit,
38 TAG => Tag,
39 _ => panic!("We currently don't support any V3 features or extensions"),
40 };
41 data::Entry {
42 header: object,
43 decompressed_size: size,
44 data_offset: pack_offset + consumed as u64,
45 }
46 }
47
48 pub fn from_read(
50 mut r: impl io::Read,
51 pack_offset: data::Offset,
52 hash_len: usize,
53 ) -> Result<data::Entry, io::Error> {
54 let (type_id, size, mut consumed) = streaming_parse_header_info(&mut r)?;
55
56 use crate::data::entry::Header::*;
57 let object = match type_id {
58 OFS_DELTA => {
59 let (distance, leb_bytes) = leb64_from_read(&mut r)?;
60 let delta = OfsDelta {
61 base_distance: distance,
62 };
63 consumed += leb_bytes;
64 delta
65 }
66 REF_DELTA => {
67 let mut buf = git_hash::Kind::buf();
68 let hash = &mut buf[..hash_len];
69 r.read_exact(hash)?;
70 #[allow(clippy::redundant_slicing)]
71 let delta = RefDelta {
72 base_id: git_hash::ObjectId::from(&hash[..]),
73 };
74 consumed += hash_len;
75 delta
76 }
77 BLOB => Blob,
78 TREE => Tree,
79 COMMIT => Commit,
80 TAG => Tag,
81 _ => panic!("We currently don't support any V3 features or extensions"),
82 };
83 Ok(data::Entry {
84 header: object,
85 decompressed_size: size,
86 data_offset: pack_offset + consumed as u64,
87 })
88 }
89}
90
91#[inline]
92fn streaming_parse_header_info(mut read: impl io::Read) -> Result<(u8, u64, usize), io::Error> {
93 let mut byte = [0u8; 1];
94 read.read_exact(&mut byte)?;
95 let mut c = byte[0];
96 let mut i = 1;
97 let type_id = (c >> 4) & 0b0000_0111;
98 let mut size = c as u64 & 0b0000_1111;
99 let mut s = 4;
100 while c & 0b1000_0000 != 0 {
101 read.read_exact(&mut byte)?;
102 c = byte[0];
103 i += 1;
104 size += ((c & 0b0111_1111) as u64) << s;
105 s += 7
106 }
107 Ok((type_id, size, i))
108}
109
110#[inline]
112fn parse_header_info(data: &[u8]) -> (u8, u64, usize) {
113 let mut c = data[0];
114 let mut i = 1;
115 let type_id = (c >> 4) & 0b0000_0111;
116 let mut size = c as u64 & 0b0000_1111;
117 let mut s = 4;
118 while c & 0b1000_0000 != 0 {
119 c = data[i];
120 i += 1;
121 size += ((c & 0b0111_1111) as u64) << s;
122 s += 7
123 }
124 (type_id, size, i)
125}