1#![no_std]
2#![doc = include_str!("../README.md")]
3
4use core::fmt;
5
6macro_rules! gen {
7 {
8 $($n:ident $p:ident)*;
9 $(
10 $name:ident : $magic:literal{
11 $($field:ident:$t:ident,)*
12 }
13 )*
14 } => {
15 $(
16 #[derive(Copy, Clone, PartialEq, Eq)]
17 pub struct $n([u8; core::mem::size_of::<$p>()]);
18 impl $n {
19 pub fn get(&self) -> $p {
20 $p::from_le_bytes(self.0)
21 }
22 #[allow(unused)]
23 const fn new(n: $p) -> Self {
24 Self(n.to_le_bytes())
25 }
26 }
27 impl fmt::Debug for $n {
28 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29 self.get().fmt(f)
30 }
31 }
32 )*
33 mod types {
34 pub use super::{CompressionMethod, $($n),*};
35 }
36 $(
37 #[repr(C)]
38 #[derive(Debug)]
39 pub struct $name {
40 $(pub $field: types::$t),*
41 }
42 impl $name {
43 pub fn as_prefix(bytes: &[u8]) -> Option<&Self> {
44 (bytes.len() >= core::mem::size_of::<Self>() + 4)
45 .then(|| unsafe { &*(bytes.as_ptr() as *const (U32, Self)) })
46 .filter(|p| p.0.get() == $magic)
47 .map(|p| &p.1)
48 }
49 pub fn as_suffix(bytes: &[u8]) -> Option<&Self> {
50 bytes.get(bytes.len() - core::mem::size_of::<Self>() - 4..).and_then(Self::as_prefix)
51 }
52 }
53 )*
54 }
55}
56gen! {
57 U16 u16 U32 u32 U64 u64;
58
59 Footer: 0x06054b50 {
60 disk_number: U16,
61 directory_start_disk: U16,
62 entries_on_this_disk: U16,
63 entries: U16,
64 directory_size: U32,
65 offset_from_start: U32,
66 comment_length: U16,
67 }
68 FooterLocator: 0x07064b50 {
69 directory_start_disk: U32,
70 footer_offset: U64,
71 disk_count: U32,
72 }
73 FooterV2: 0x06064b50 {
74 footer_size: U64,
75 made_by: U16,
76 required_version: U16,
77 disk_number: U32,
78 directory_start_disk: U32,
79 entries_on_this_disk: U64,
80 entries: U64,
81 directory_size: U64,
82 offset_from_start: U64,
83 }
84 DirectoryEntry: 0x02014b50 {
85 made_by: U16,
86 required_version: U16,
87 flags: U16,
88 method: CompressionMethod,
89 modified_time: U16,
90 modified_date: U16,
91 crc32: U32,
92 compressed_size: U32,
93 uncompressed_size: U32,
94 name_len: U16,
95 metadata_len: U16,
96 comment_len: U16,
97
98 disk_number: U16,
99 internal_attrs: U16,
100 external_attrs: U32,
101 offset_from_start: U32,
102 }
103 Header: 0x04034b50 {
104 required_version: U16,
105 flags: U16,
106 method: CompressionMethod,
107 modified_time: U16,
108 modified_date: U16,
109 crc32: U32,
110 compressed_size: U32,
111 uncompressed_size: U32,
112 name_len: U16,
113 metadata_len: U16,
114 }
115}
116
117#[repr(transparent)]
118#[derive(Copy, Clone, PartialEq, Eq)]
119pub struct CompressionMethod(U16);
120impl CompressionMethod {
121 pub const STORED: Self = Self(U16::new(0));
122 pub const DEFLATE: Self = Self(U16::new(8));
123}
124
125impl fmt::Debug for CompressionMethod {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 write!(f, "CompressionMethod({})", self.0.get())
128 }
129}
130impl fmt::Display for CompressionMethod {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.write_str(match self.0.get() {
138 0 => "no compression",
139
140 1 => "a deprecated method (shrunk)",
141 2 => "a deprecated method (reduced with factor 1)",
142 3 => "a deprecated method (reduced with factor 2)",
143 4 => "a deprecated method (reduced with factor 3)",
144 5 => "a deprecated method (reduced with factor 4)",
145 6 => "a deprecated method (imploded)",
146
147 7 => "a reserved method (PKWARE tokenizing algorithm)",
148 11 => "a reserved method (11)",
149 13 => "a reserved method (13)",
150 15 => "a reserved method (15)",
151 17 => "a reserved method (17)",
152
153 8 => "deflate compression",
154 9 => "deflate64 compression",
155 10 => "PKWARE TERSE",
156 12 => "BZIP2 compression",
157 14 => "LZMA compression",
158 16 => "IBM z/OS CMPSC compression",
159 18 => "IBM TERSE",
160 19 => "LZ77 compression",
161
162 20 => "a deprecated method (zstd)",
163
164 93 => "zstd compression",
165 94 => "MP3 encoding",
166 95 => "XZ compression",
167 96 => "JPEG encoding",
168 97 => "WavPack compression",
169 98 => "PPMd compression",
170
171 99 => "AE-x encryption",
172
173 v => return write!(f, "an unknown method ({v})"),
174 })
175 }
176}