1pub struct VersionMadeBy {
8 pub compatibility_information: CompatibleFileAttributeInformation,
9 pub version: ZipVersion,
10}
11
12#[derive(Debug, Clone, PartialEq)]
16pub enum CompatibleFileAttributeInformation {
17 MsDosAndOs2,
19 Amiga,
20 OpenVms,
21 Unix,
22 VmCms,
23 AtariSt,
24 Os2,
25 Macintosh,
26 ZSystem,
27 CpM,
28 WindowsNtfs,
29 Mvs,
30 Vse,
31 AcornRisc,
32 VFat,
33 AlternateMvs,
34 BeOs,
35 Tandem,
36 Os400,
37 OsX,
38}
39
40impl TryFrom<u8> for CompatibleFileAttributeInformation {
41 type Error = u8;
42
43 fn try_from(value: u8) -> Result<Self, Self::Error> {
47 use CompatibleFileAttributeInformation::*;
48 match value {
49 0 => Ok(MsDosAndOs2),
50 1 => Ok(Amiga),
51 2 => Ok(OpenVms),
52 3 => Ok(Unix),
53 4 => Ok(VmCms),
54 5 => Ok(AtariSt),
55 6 => Ok(Os2),
56 7 => Ok(Macintosh),
57 8 => Ok(ZSystem),
58 9 => Ok(CpM),
59 10 => Ok(WindowsNtfs),
60 11 => Ok(Mvs),
61 12 => Ok(Vse),
62 13 => Ok(AcornRisc),
63 14 => Ok(VFat),
64 15 => Ok(AlternateMvs),
65 16 => Ok(BeOs),
66 17 => Ok(Tandem),
67 18 => Ok(Os400),
68 19 => Ok(OsX),
69 other => Err(other),
70 }
71 }
72}
73
74#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
75pub struct ZipVersion {
76 pub major_version: u8,
77 pub minor_version: u8,
78}
79
80impl From<u8> for ZipVersion {
82 fn from(value: u8) -> Self {
83 let major_version = value / 10;
84 let minor_version = value.rem_euclid(10);
85 Self {
86 major_version,
87 minor_version,
88 }
89 }
90}
91
92impl From<u16> for ZipVersion {
94 fn from(value: u16) -> Self {
95 let version = value.to_le_bytes();
96 Self {
97 major_version: version[0],
98 minor_version: version[1],
99 }
100 }
101}
102
103impl ZipVersion {
104 pub fn new(major_version: u8, minor_version: u8) -> Self {
105 Self {
106 major_version,
107 minor_version,
108 }
109 }
110}
111
112#[derive(Debug, Clone, PartialEq)]
114pub enum MinimumFeatureVersion {
115 Default,
116 VolumeLabel,
117 Folder,
118 CompressedUsingDeflate,
119 EncryptedUsingPkWare,
120 CompressedUsingDeflate64,
121 CompressedUsingPkwareDclImplode,
122 PatchDataSet,
123 UsesZip64FormatExtentions,
124 CompressedUsingBzip2,
125 EncryptedUsingDes,
126 EncryptedUsing3Des,
127 EncryptedUsingOriginalRc2,
128 EncryptedUsingRc4,
129 EncryptedUsingAes,
130 EncryptedUsingCorrectedRc2,
131 EncryptedUsingCorrectedRc2_64,
132 EncryptedUsingNonOaepKeyWrapping,
133 CentralDirectoryEncryption,
134 CompressedUsingLzma,
135 CompressedUsingPpmd,
136 EncryptedUsingBlowfish,
137 EncryptedUsingTwofish,
138}
139
140impl From<MinimumFeatureVersion> for ZipVersion {
141 fn from(value: MinimumFeatureVersion) -> Self {
142 use MinimumFeatureVersion::*;
143 match value {
144 Default => ZipVersion::new(1, 0),
145 VolumeLabel => ZipVersion::new(1, 1),
146 Folder => ZipVersion::new(2, 0),
147 CompressedUsingDeflate => ZipVersion::new(2, 0),
148 EncryptedUsingPkWare => ZipVersion::new(2, 0),
149 CompressedUsingDeflate64 => ZipVersion::new(2, 1),
150 CompressedUsingPkwareDclImplode => ZipVersion::new(2, 5),
151 PatchDataSet => ZipVersion::new(2, 7),
152 UsesZip64FormatExtentions => ZipVersion::new(4, 5),
153 CompressedUsingBzip2 => ZipVersion::new(4, 7),
154 EncryptedUsingDes => ZipVersion::new(5, 0),
155 EncryptedUsing3Des => ZipVersion::new(5, 0),
156 EncryptedUsingOriginalRc2 => ZipVersion::new(5, 0),
157 EncryptedUsingRc4 => ZipVersion::new(5, 0),
158 EncryptedUsingAes => ZipVersion::new(5, 1),
159 EncryptedUsingCorrectedRc2 => ZipVersion::new(5, 1),
160 EncryptedUsingCorrectedRc2_64 => ZipVersion::new(5, 2),
161 EncryptedUsingNonOaepKeyWrapping => ZipVersion::new(6, 1),
162 CentralDirectoryEncryption => ZipVersion::new(6, 2),
163 CompressedUsingLzma => ZipVersion::new(6, 3),
164 CompressedUsingPpmd => ZipVersion::new(6, 3),
165 EncryptedUsingBlowfish => ZipVersion::new(6, 3),
166 EncryptedUsingTwofish => ZipVersion::new(6, 3),
167 }
168 }
169}
170
171#[derive(Debug, Clone, PartialEq)]
173pub enum CompressionMethod {
174 Stored,
175 Shrunk,
176 ReducedWithFactor1,
177 ReducedWithFactor2,
178 ReducedWithFactor3,
179 ReducedWithFactor4,
180 Imploded,
181 Deflated,
182 EnhancedDeflatingUsingDeflate64,
183 PkWareDataCompressionLIbraryImploding,
184 Bzip2,
185 Lzma,
186 IbmZOsCmpsc,
187 IbmTerse,
189 IbmLz77z,
190 Zstdandart,
191 Mp3,
192 Xz,
193 Jpeg,
194 WavPack,
195 PpmdV1R1,
196 Aex,
197}
198
199impl CompressionMethod {
200 pub const fn is_deprecated(&self) -> bool {
201 use CompressionMethod::*;
202 matches!(
203 self,
204 Shrunk | ReducedWithFactor1 | ReducedWithFactor2 | ReducedWithFactor3 | ReducedWithFactor4 | Imploded
205 )
206 }
207}
208
209impl TryFrom<u16> for CompressionMethod {
210 type Error = u16;
211
212 fn try_from(value: u16) -> Result<Self, Self::Error> {
216 use CompressionMethod::*;
217 match value {
218 0 => Ok(Stored),
219 1 => Ok(Shrunk),
220 2 => Ok(ReducedWithFactor1),
221 3 => Ok(ReducedWithFactor2),
222 4 => Ok(ReducedWithFactor3),
223 5 => Ok(ReducedWithFactor4),
224 6 => Ok(Imploded),
225 8 => Ok(Deflated),
226 9 => Ok(EnhancedDeflatingUsingDeflate64),
227 10 => Ok(PkWareDataCompressionLIbraryImploding),
228 12 => Ok(Bzip2),
229 14 => Ok(Lzma),
230 16 => Ok(IbmZOsCmpsc),
231 18 => Ok(IbmTerse),
232 19 => Ok(IbmLz77z),
233 93 => Ok(Zstdandart),
234 94 => Ok(Mp3),
235 95 => Ok(Xz),
236 96 => Ok(Jpeg),
237 97 => Ok(WavPack),
238 98 => Ok(PpmdV1R1),
239 99 => Ok(Aex),
240 other => Err(other),
241 }
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use super::*;
248
249 #[test]
250 fn order_zip_version() {
251 let v1_0 = ZipVersion::new(1, 0);
252 let v1_1 = ZipVersion::new(1, 1);
253 let v2_0 = ZipVersion::new(2, 0);
254 let v2_1 = ZipVersion::new(2, 1);
255 assert_eq!(v1_0, v1_0);
256 assert_ne!(v1_0, v1_1);
257 assert_ne!(v1_1, v2_1);
258
259 assert!(v1_1 > v1_0);
260 assert!(v2_0 > v1_0);
261 assert!(v2_0 > v1_1);
262 assert!(v2_1 > v2_0);
263 assert!(v2_0 <= v2_0);
264 assert!(v2_0 < v2_1);
265 assert!(v1_1 < v2_1);
266 assert!(v1_0 < v2_1);
267 assert_eq!(v1_0.max(v1_1), v1_1);
268 }
269
270 #[test]
271 fn parse_zip_version() {
272 assert_eq!(ZipVersion::from(30u8), ZipVersion::new(3, 0));
273 assert_eq!(ZipVersion::from(19u8), ZipVersion::new(1, 9));
274 assert_eq!(ZipVersion::from(123u8), ZipVersion::new(12, 3));
275 assert_eq!(ZipVersion::from(1u16), ZipVersion::new(1, 0));
276 assert_eq!(ZipVersion::from(258u16), ZipVersion::new(2, 1));
277 assert_eq!(ZipVersion::from(259u16), ZipVersion::new(3, 1));
278 }
279
280 #[test]
281 fn parse_compatible_file_attribute_infromation() {
282 use CompatibleFileAttributeInformation::*;
283 assert_eq!(CompatibleFileAttributeInformation::try_from(0).unwrap(), MsDosAndOs2);
284 assert_eq!(CompatibleFileAttributeInformation::try_from(19).unwrap(), OsX);
285 assert_eq!(CompatibleFileAttributeInformation::try_from(123), Err(123));
286
287 assert!(CompatibleFileAttributeInformation::try_from(1).is_ok());
289 assert!(CompatibleFileAttributeInformation::try_from(2).is_ok());
290 assert!(CompatibleFileAttributeInformation::try_from(3).is_ok());
291 assert!(CompatibleFileAttributeInformation::try_from(4).is_ok());
292 assert!(CompatibleFileAttributeInformation::try_from(5).is_ok());
293 assert!(CompatibleFileAttributeInformation::try_from(6).is_ok());
294 assert!(CompatibleFileAttributeInformation::try_from(7).is_ok());
295 assert!(CompatibleFileAttributeInformation::try_from(8).is_ok());
296 assert!(CompatibleFileAttributeInformation::try_from(9).is_ok());
297 assert!(CompatibleFileAttributeInformation::try_from(10).is_ok());
298 assert!(CompatibleFileAttributeInformation::try_from(11).is_ok());
299 assert!(CompatibleFileAttributeInformation::try_from(12).is_ok());
300 assert!(CompatibleFileAttributeInformation::try_from(13).is_ok());
301 assert!(CompatibleFileAttributeInformation::try_from(14).is_ok());
302 assert!(CompatibleFileAttributeInformation::try_from(15).is_ok());
303 assert!(CompatibleFileAttributeInformation::try_from(16).is_ok());
304 assert!(CompatibleFileAttributeInformation::try_from(17).is_ok());
305 assert!(CompatibleFileAttributeInformation::try_from(18).is_ok());
306 assert!(CompatibleFileAttributeInformation::try_from(20).is_err());
307 assert!(CompatibleFileAttributeInformation::try_from(21).is_err());
308 assert!(CompatibleFileAttributeInformation::try_from(22).is_err());
309 assert!(CompatibleFileAttributeInformation::try_from(23).is_err());
310 assert!(CompatibleFileAttributeInformation::try_from(55).is_err());
311 assert!(CompatibleFileAttributeInformation::try_from(200).is_err());
312 assert!(CompatibleFileAttributeInformation::try_from(255).is_err());
313 }
314
315 #[test]
316 fn parse_minimum_feature_version() {
317 use MinimumFeatureVersion::*;
318 assert_eq!(ZipVersion::from(Default), ZipVersion::new(1, 0));
319 assert_eq!(ZipVersion::from(CompressedUsingDeflate64), ZipVersion::new(2, 1));
320 assert_eq!(ZipVersion::from(UsesZip64FormatExtentions), ZipVersion::new(4, 5));
321 assert_eq!(ZipVersion::from(EncryptedUsingDes), ZipVersion::new(5, 0));
322 assert_eq!(ZipVersion::from(CentralDirectoryEncryption), ZipVersion::new(6, 2));
323 assert_eq!(ZipVersion::from(CompressedUsingLzma), ZipVersion::new(6, 3));
324 }
325
326 #[test]
327 fn parse_compression_method() {
328 use CompressionMethod::*;
329 assert_eq!(CompressionMethod::try_from(0).unwrap(), Stored);
330 assert_eq!(CompressionMethod::try_from(9).unwrap(), EnhancedDeflatingUsingDeflate64);
331 assert_eq!(CompressionMethod::try_from(15), Err(15));
332 assert_eq!(CompressionMethod::try_from(93).unwrap(), Zstdandart);
333 assert_eq!(CompressionMethod::try_from(200), Err(200));
334
335 assert!(CompressionMethod::try_from(1).is_ok());
337 assert!(CompressionMethod::try_from(2).is_ok());
338 assert!(CompressionMethod::try_from(3).is_ok());
339 assert!(CompressionMethod::try_from(4).is_ok());
340 assert!(CompressionMethod::try_from(5).is_ok());
341 assert!(CompressionMethod::try_from(6).is_ok());
342 assert!(CompressionMethod::try_from(7).is_err());
343 assert!(CompressionMethod::try_from(8).is_ok());
344 assert!(CompressionMethod::try_from(9).is_ok());
345 assert!(CompressionMethod::try_from(10).is_ok());
346 assert!(CompressionMethod::try_from(11).is_err());
347 assert!(CompressionMethod::try_from(12).is_ok());
348 assert!(CompressionMethod::try_from(13).is_err());
349 assert!(CompressionMethod::try_from(14).is_ok());
350 assert!(CompressionMethod::try_from(16).is_ok());
351 assert!(CompressionMethod::try_from(17).is_err());
352 assert!(CompressionMethod::try_from(18).is_ok());
353 assert!(CompressionMethod::try_from(19).is_ok());
354 assert!(CompressionMethod::try_from(20).is_err());
355 assert!(CompressionMethod::try_from(21).is_err());
356 assert!(CompressionMethod::try_from(22).is_err());
357 assert!(CompressionMethod::try_from(92).is_err());
358 assert!(CompressionMethod::try_from(93).is_ok());
359 assert!(CompressionMethod::try_from(94).is_ok());
360 assert!(CompressionMethod::try_from(95).is_ok());
361 assert!(CompressionMethod::try_from(96).is_ok());
362 assert!(CompressionMethod::try_from(97).is_ok());
363 assert!(CompressionMethod::try_from(98).is_ok());
364 assert!(CompressionMethod::try_from(99).is_ok());
365 assert!(CompressionMethod::try_from(100).is_err());
366 assert!(CompressionMethod::try_from(200).is_err());
367 assert!(CompressionMethod::try_from(255).is_err());
368
369 assert!(!Stored.is_deprecated());
370 assert!(ReducedWithFactor3.is_deprecated());
371 }
372}