use std::fmt::Debug; use std::convert::TryFrom; use enumflags2::BitFlags; use crate::error::*; pub type Id = [u8; 2]; pub type SubfieldId = [u8; 2]; pub type Name = String; pub type Comment = String; pub type Crc16 = u16; pub type Crc32 = u32; #[derive(BitFlags, Debug, Copy, Clone, PartialEq)] #[repr(u8)] pub enum Flags { Text = 1, HeaderCrc = 2, Extra = 4, Name = 8, Comment = 16, Reserved0 = 32, Reserved1 = 64, Reserved2 = 128, } #[derive(BitFlags, Debug, Copy, Clone, PartialEq)] #[repr(u8)] pub enum CompressionFlags { BestCompression = 2, FastestCompression = 4, } #[derive(Debug, Copy, Clone, PartialEq)] #[repr(u8)] pub enum CompressionMethod { Reserved0 = 0, Reserved1 = 1, Reserved2 = 2, Reserved3 = 3, Reserved4 = 4, Reserved5 = 5, Reserved6 = 6, Reserved7 = 7, Deflate = 8, } impl TryFrom<u8> for CompressionMethod { type Error = Error; fn try_from(byte: u8) -> std::result::Result<Self, Self::Error> { use CompressionMethod::*; match byte { 0 => Ok(Reserved0), 1 => Ok(Reserved1), 2 => Ok(Reserved2), 3 => Ok(Reserved3), 4 => Ok(Reserved4), 5 => Ok(Reserved5), 6 => Ok(Reserved6), 7 => Ok(Reserved7), 8 => Ok(Deflate), _ => Err(Error(ErrorKind::InvalidCompressionMethod, None)), } } } impl Default for CompressionMethod { fn default() -> Self { CompressionMethod::Deflate } } #[derive(Debug, Copy, Clone, PartialEq)] #[repr(u8)] pub enum OperatingSystem { Fat = 0, Amiga = 1, Vms = 2, Unix = 3, VmCms = 4, Atari = 5, Hpfs = 6, Macintosh = 7, ZSystem = 8, Cpm = 9, Tops = 10, Ntfs = 11, Qdos = 12, Acorn = 13, Unknown = 255, } impl Default for OperatingSystem { fn default() -> Self { OperatingSystem::Unknown } } impl TryFrom<u8> for OperatingSystem { type Error = Error; fn try_from(byte: u8) -> std::result::Result<Self, Self::Error> { use OperatingSystem::*; match byte { 0 => Ok(Fat), 1 => Ok(Amiga), 2 => Ok(Vms), 3 => Ok(Unix), 4 => Ok(VmCms), 5 => Ok(Atari), 6 => Ok(Hpfs), 7 => Ok(Macintosh), 8 => Ok(ZSystem), 9 => Ok(Cpm), 10 => Ok(Tops), 11 => Ok(Ntfs), 12 => Ok(Qdos), 13 => Ok(Acorn), 155 => Ok(Unknown), _ => Err(Error(ErrorKind::InvalidCompressionMethod, None)), } } } #[derive(Debug, Copy, Clone, PartialEq)] pub enum SubFieldType { ApolloFileTypeInformation, } impl From<SubFieldType> for [u8; 2] { fn from(t: SubFieldType) -> Self { use SubFieldType::*; match t { ApolloFileTypeInformation => [0x41, 0x70], // AP } } } impl Header { pub const GZIP_ID: [u8; 2] = [0x1f, 0x8b]; } #[derive(Default, Debug, Clone)] pub struct Extra { pub length: u16, pub subfield_id: SubfieldId, pub data_length: u16, pub data: Vec<u8>, } #[derive(Default, Debug, Clone)] pub struct Header { pub id: Id, pub compression_method: CompressionMethod, pub flags: BitFlags<Flags>, pub modification_time: u32, pub compression_flags: BitFlags<CompressionFlags>, pub operating_system: OperatingSystem, pub extra: Option<Extra>, pub name: Option<Name>, pub comment: Option<Comment>, pub crc: Option<Crc16>, } #[derive(Default, Clone)] pub struct Member { pub header: Header, pub data: Vec<u8>, pub crc: Crc32, pub input_size: u32, } impl Debug for Member { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { f.debug_struct("GZIP Member") .field("Header", &self.header) .field("Read Data Size", &self.data.len()) .field("Input Size", &self.input_size) .field("CRC32", &self.crc) .finish() } }