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],
}
}
}
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()
}
}