zip/extra_fields/
zipinfo_utf8.rs1use crate::result::{ZipResult, invalid};
2use crate::unstable::LittleEndianReadExt;
3use core::mem;
4use std::io::{Read, Write};
5
6#[derive(Clone, Debug, PartialEq)]
9pub struct UnicodeExtraField {
10 crc32: u32,
11 pub(crate) content: Box<[u8]>,
12}
13
14impl UnicodeExtraField {
15 pub fn unwrap_valid(self, ascii_field: &[u8]) -> ZipResult<Box<[u8]>> {
22 let computed_crc32 = crc32fast::hash(ascii_field);
23 if self.crc32 != computed_crc32 {
24 return Err(invalid!(
25 "CRC32 checksum failed on Unicode extra field, it is '{:#08X}' and it should be '{:#08X}'",
26 self.crc32,
27 computed_crc32
28 ));
29 }
30 Ok(self.content)
31 }
32
33 pub(crate) fn is_crc32_valid(&self, ascii_field: &[u8]) -> bool {
35 let computed_crc32 = crc32fast::hash(ascii_field);
36 self.crc32 == computed_crc32
37 }
38
39 pub(crate) fn try_from_reader<R: Read>(reader: &mut R, len: u16) -> ZipResult<Self> {
40 reader.read_exact(&mut [0u8])?;
42
43 let crc32 = reader.read_u32_le()?;
44 let content_len = (len as usize)
45 .checked_sub(mem::size_of::<u8>() + mem::size_of::<u32>())
46 .ok_or(invalid!("Unicode extra field is too small"))?;
47 let mut content = vec![0u8; content_len].into_boxed_slice();
48 reader.read_exact(&mut content)?;
49 Ok(Self { crc32, content })
50 }
51
52 pub(crate) fn full_size(&self) -> usize {
53 mem::size_of::<u16>() + mem::size_of::<u16>() + self.size()
56 }
57
58 pub(crate) fn size(&self) -> usize {
59 mem::size_of::<u8>() + mem::size_of::<u32>() + self.content.len() }
63
64 pub(crate) fn write<W: Write>(&self, writer: &mut W) -> ZipResult<()> {
66 let size = self.size() as u16;
68 writer.write_all(&size.to_le_bytes())?;
69 let version = 1u8;
70 writer.write_all(&version.to_le_bytes())?;
71 writer.write_all(&self.crc32.to_le_bytes())?;
72 writer.write_all(&self.content)?;
73 Ok(())
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use crate::extra_fields::UnicodeExtraField;
80 #[test]
81 fn unicode_extra_field_crc32_correct() {
82 let data = [0x01, 0xef, 0x39, 0x8e, 0x4b, b'u', b't', b'f', b'-', b'8'];
83 let extra =
84 UnicodeExtraField::try_from_reader(&mut std::io::Cursor::new(data), 10).unwrap();
85 let res = extra.unwrap_valid(b"abcdef");
86 assert!(res.is_ok());
87 let content = res.unwrap();
88 assert_eq!(content.as_ref(), b"utf-8");
89 }
90
91 #[test]
92 fn unicode_extra_field_crc32_incorrect() {
93 let data = [0x01, 0x00, 0x00, 0x00, 0x00, b'u', b't', b'f', b'-', b'8'];
94 let extra =
95 UnicodeExtraField::try_from_reader(&mut std::io::Cursor::new(data), 10).unwrap();
96 let res = extra.unwrap_valid(b"abcdef");
97 assert!(res.is_err());
98 }
99
100 #[test]
101 fn unicode_extra_field_write_test() {
102 let data = [0x01, 0xef, 0x39, 0x8e, 0x4b, b'u', b't', b'f', b'-', b'8'];
103 assert_eq!(data.len(), 10); let extra =
105 UnicodeExtraField::try_from_reader(&mut std::io::Cursor::new(data), 10).unwrap();
106 let mut data = Vec::new();
107 extra.write(&mut data).unwrap();
108
109 assert_eq!(
112 data,
113 [
114 0x0A, 0x00, 0x01, 0xef, 0x39, 0x8e, 0x4b, b'u', b't', b'f', b'-', b'8'
115 ]
116 );
117 }
118}