1#[cfg(feature = "read")]
2use crate::{Error, ObjectFormat, Result};
3
4#[cfg(any(feature = "read", feature = "write"))]
5mod crc;
6#[cfg(any(feature = "read", feature = "write"))]
7pub use crc::crc32;
8
9#[cfg(any(feature = "read", feature = "write"))]
10mod index_entry;
11#[cfg(any(feature = "read", feature = "write"))]
12pub use index_entry::IndexEntry;
13
14#[cfg(feature = "read")]
15mod index_lookup;
16#[cfg(feature = "read")]
17pub use index_lookup::{IndexHeader, IndexLookup, IndexRange, LookupStatus};
18
19#[cfg(feature = "read")]
20mod decode;
21#[cfg(feature = "read")]
22pub use decode::{DeltaLimits, Entry, EntryHeader, EntryKind, Reader, ResolvedObject, apply_delta};
23
24#[cfg(feature = "read")]
25mod delta;
26#[cfg(feature = "read")]
27pub use delta::{DeltaDecoder, DeltaProgress, DeltaStatus};
28
29#[cfg(feature = "read")]
30mod range;
31#[cfg(feature = "read")]
32pub use range::{
33 ObjectKey, ObjectRange, RangeFrame, RangeInput, RangeLimits, RangeObject, RangeProgress,
34 RangeRepresentation, RangeRequest, RangeResolver,
35};
36
37#[cfg(feature = "read")]
38mod receive;
39#[cfg(feature = "read")]
40pub use receive::{DecodeLimits, DecodeProgress, DecodeStatus, Decoder, EntryDecoder};
41
42#[cfg(feature = "read")]
43mod entry_range;
44#[cfg(feature = "read")]
45pub use entry_range::{ByteRange, EntryRangeDecoder, EntryRangeProgress, EntryRangeStatus};
46
47#[cfg(feature = "read")]
48mod materialize;
49#[cfg(feature = "read")]
50pub use materialize::{
51 MaterializeLimits, MaterializedEntry, MaterializedPack, find_materialized, materialize,
52};
53
54#[cfg(feature = "write")]
55mod index;
56#[cfg(feature = "write")]
57pub use index::{write_index, write_indexed_with_scratch};
58
59#[cfg(feature = "write")]
60mod index_stream;
61#[cfg(feature = "write")]
62pub use index_stream::IndexEncoder;
63
64#[cfg(feature = "write")]
65mod encode;
66#[cfg(feature = "write")]
67mod stream;
68#[cfg(feature = "write")]
69pub use encode::{
70 write, write_loose, write_loose_with_scratch, write_selected_with_scratch, write_with_scratch,
71};
72#[cfg(feature = "write")]
73pub use stream::{Encoder, LooseEncoder};
74
75#[cfg(feature = "write")]
76mod reuse;
77#[cfg(feature = "write")]
78pub use reuse::{CompressedEntry, CompressedKind, PackComposer};
79
80#[cfg(feature = "read")]
83pub fn validate(bytes: &[u8]) -> Result<()> {
84 validate_with_format(bytes, ObjectFormat::Sha1)
85}
86
87#[cfg(feature = "read")]
88pub fn validate_with_format(bytes: &[u8], format: ObjectFormat) -> Result<()> {
89 if bytes.len() < 12 + format.id_length()
90 || &bytes[..4] != b"PACK"
91 || !matches!(&bytes[4..8], [0, 0, 0, 2] | [0, 0, 0, 3])
92 {
93 return Err(Error::CorruptPack);
94 }
95 let trailer = bytes.len() - format.id_length();
96 let actual = format
97 .digest(&bytes[..trailer])
98 .map_err(|_| Error::CorruptPack)?;
99 if actual.as_bytes() != &bytes[trailer..] {
100 return Err(Error::CorruptPack);
101 }
102 Ok(())
103}