git_plumber/git/pack/
mod.rs1use nom::{
2 IResult, Parser,
3 bytes::complete::tag,
4 combinator::map,
5 error::{Error, ErrorKind},
6 number::complete::be_u32,
7};
8
9pub mod delta;
10pub mod index;
11pub mod object;
12
13pub use delta::{DeltaInstruction, parse_delta_instructions};
14pub use index::PackIndex;
15pub use object::{Object, ObjectHeader, ObjectType};
16
17use thiserror::Error;
18
19#[derive(Debug)]
20pub struct Header {
21 pub version: u32,
22 pub object_count: u32,
23 pub raw_data: Vec<u8>,
24}
25
26impl Header {
27 fn parse_signature(input: &[u8]) -> IResult<&[u8], ()> {
30 map(tag("PACK"), |_| ()).parse(input)
31 }
32
33 pub fn parse(input: &[u8]) -> IResult<&[u8], Self> {
37 let original_input = input;
38 let (input, ()) = Self::parse_signature(input)?;
39 let (input, version) = be_u32(input)?;
40
41 if version != 2 && version != 3 {
42 return Err(nom::Err::Error(Error::new(input, ErrorKind::Tag)));
43 }
44
45 let (input, object_count) = be_u32(input)?;
46
47 let header_size = original_input.len() - input.len();
49 let raw_data = original_input[..header_size].to_vec();
50
51 Ok((
52 input,
53 Header {
54 version,
55 object_count,
56 raw_data,
57 },
58 ))
59 }
60}
61
62#[derive(Debug, Error)]
63pub enum PackError {
64 #[error("Invalid pack file signature")]
65 InvalidSignature,
66
67 #[error("Unsupported pack version: {0}")]
68 UnsupportedVersion(u32),
69
70 #[error("Invalid object type: {0}")]
71 InvalidObjectType(u8),
72
73 #[error("Parse error: {0}")]
74 ParseError(String),
75
76 #[error("Decompression error: {0}")]
77 DecompressionError(#[from] std::io::Error),
78
79 #[error("Invalid index file signature")]
81 InvalidIndexSignature,
82
83 #[error("Unsupported index version: {0}")]
84 UnsupportedIndexVersion(u32),
85
86 #[error("Corrupt fan-out table")]
87 CorruptFanOutTable,
88
89 #[error("Index checksum mismatch")]
90 IndexChecksumMismatch,
91
92 #[error("Pack checksum mismatch")]
93 PackChecksumMismatch,
94
95 #[error("Object not found in index: {0}")]
96 ObjectNotFound(String),
97
98 #[error("Invalid object index: {0}")]
99 InvalidObjectIndex(usize),
100}
101
102#[cfg(test)]
104mod tests {
105 use super::*;
106 fn create_pack_header(object_count: u32) -> Vec<u8> {
107 let mut header = Vec::new();
108 header.extend_from_slice(b"PACK"); header.extend_from_slice(&[0, 0, 0, 2]); header.extend_from_slice(&object_count.to_be_bytes()); header
112 }
113
114 #[test]
115 fn parse_pack_header() {
116 let data = create_pack_header(3); let (_, header) = Header::parse(&data).unwrap();
118 assert_eq!(header.version, 2);
119 assert_eq!(header.object_count, 3);
120
121 assert_eq!(header.raw_data.len(), 12); assert_eq!(&header.raw_data[0..4], b"PACK"); assert_eq!(&header.raw_data[4..8], &[0, 0, 0, 2]); assert_eq!(&header.raw_data[8..12], &3u32.to_be_bytes()); }
127}