an efficient binary archive format
1use zerocopy::{FromBytes, Immutable, IntoBytes, Unaligned};
2
3use crate::compress::Compress;
4
5/// Metadata for an entry in the archive.
6///
7/// Contains information about stored files including offset, size, compression, and CRC32 checksum.
8/// Retrieved via the archive's `index()` method.
9#[repr(C, packed)]
10#[derive(FromBytes, Unaligned, IntoBytes, Immutable, Clone, Copy, Debug, Default)]
11pub struct Entry {
12 offset: u64,
13 compressed_size: u64,
14 uncompressed_size: u64,
15 crc32: u32,
16 name_len: u16,
17 pub compression_type: u8,
18 pub _reserved: u8,
19}
20
21// The binary format uses little-endian byte order for all multi-byte integers.
22// These methods handle endianness conversion transparently:
23// - On little-endian systems (x86, ARM): zero overhead, direct access
24// - On big-endian systems: bytes are swapped to/from little-endian
25
26impl Entry {
27 /// Returns the byte offset where this entry's data starts in the archive.
28 pub fn offset(&self) -> u64 {
29 u64::from_le(self.offset)
30 }
31
32 pub(crate) fn set_offset(&mut self, value: u64) {
33 self.offset = value.to_le();
34 }
35
36 /// Returns the compressed size of this entry in bytes.
37 pub fn compressed_size(&self) -> u64 {
38 u64::from_le(self.compressed_size)
39 }
40
41 pub(crate) fn set_compressed_size(&mut self, value: u64) {
42 self.compressed_size = value.to_le();
43 }
44
45 /// Returns the uncompressed size of this entry in bytes.
46 pub fn uncompressed_size(&self) -> u64 {
47 u64::from_le(self.uncompressed_size)
48 }
49
50 pub(crate) fn set_uncompressed_size(&mut self, value: u64) {
51 self.uncompressed_size = value.to_le();
52 }
53
54 /// Returns the CRC32 checksum of the uncompressed data.
55 pub fn crc32(&self) -> u32 {
56 u32::from_le(self.crc32)
57 }
58
59 pub(crate) fn set_crc32(&mut self, value: u32) {
60 self.crc32 = value.to_le();
61 }
62
63 /// Returns the length of the entry name in bytes.
64 pub fn name_len(&self) -> usize {
65 u16::from_le(self.name_len) as usize
66 }
67
68 pub(crate) fn set_name_len(&mut self, value: u16) {
69 self.name_len = value.to_le();
70 }
71
72 /// Returns the compression type for this entry.
73 pub fn compression_type(&self) -> Compress {
74 Compress::from_u8(self.compression_type)
75 }
76}
77
78#[repr(C, packed)]
79#[derive(FromBytes, Unaligned, IntoBytes, Immutable, Debug)]
80pub(crate) struct Footer {
81 pub index_offset: u64,
82 pub entry_count: u32,
83 pub magic: u32,
84}
85
86impl Footer {
87 pub fn new(index_offset: u64, entry_count: u32, magic: u32) -> Self {
88 Self {
89 index_offset: index_offset.to_le(),
90 entry_count: entry_count.to_le(),
91 magic: magic.to_le(),
92 }
93 }
94
95 pub fn index_offset(&self) -> u64 {
96 u64::from_le(self.index_offset)
97 }
98
99 pub fn entry_count(&self) -> u32 {
100 u32::from_le(self.entry_count)
101 }
102
103 pub fn magic(&self) -> u32 {
104 u32::from_le(self.magic)
105 }
106}