axfive_libzip/
file.rs

1use crate::archive::Archive;
2use crate::error::ZipErrorT;
3use crate::ffi;
4use crate::Error;
5use crate::Result;
6use std::io;
7use std::marker::PhantomData;
8use std::ptr::null_mut;
9
10#[derive(Clone, Copy, PartialEq, Eq, Hash)]
11pub enum Encoding {
12    Guess,
13    Utf8,
14    Cp437,
15}
16
17#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
18pub enum Compression {
19    #[default]
20    Default,
21    Store,
22    Bzip2(u32),
23    Deflate(u32),
24    Xz(u32),
25    Zstd(u32),
26}
27
28#[derive(Clone, Copy, PartialEq, Eq, Hash)]
29pub enum OpenFlag {
30    Compressed,
31    Unchanged,
32}
33
34#[derive(Clone, Copy, PartialEq, Eq, Hash)]
35pub enum LocateFlag {
36    NoCase,
37    NoDir,
38    EncodingRaw,
39    EncodingGuess,
40    EncodingStrict,
41}
42
43#[derive(Debug)]
44pub struct File<'a> {
45    pub(crate) handle: *mut ffi::zip_file_t,
46    pub(crate) phantom: PhantomData<Archive<'a>>,
47}
48
49impl File<'_> {
50    fn error(&mut self) -> ZipErrorT<&mut ffi::zip_error_t> {
51        unsafe {
52            let error = ffi::zip_file_get_error(self.handle);
53            (&mut *error).into()
54        }
55    }
56
57    pub fn close(mut self) -> Result<()> {
58        if self.handle.is_null() {
59            Ok(())
60        } else {
61            let result = unsafe { ffi::zip_fclose(self.handle) };
62            self.handle = null_mut();
63            if result == 0 {
64                Ok(())
65            } else {
66                let error: ZipErrorT<_> = result.into();
67                Err(error.into())
68            }
69        }
70    }
71}
72impl Drop for File<'_> {
73    fn drop(&mut self) {
74        if !self.handle.is_null() {
75            unsafe {
76                ffi::zip_fclose(self.handle);
77            }
78        }
79    }
80}
81
82impl io::Read for File<'_> {
83    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
84        let result = unsafe { ffi::zip_fread(self.handle, buf.as_mut_ptr() as _, buf.len() as _) };
85        if result == -1 {
86            let error: Error = self.error().into();
87            Err(io::Error::new(io::ErrorKind::Other, error))
88        } else {
89            Ok(result as _)
90        }
91    }
92}
93
94impl io::Seek for File<'_> {
95    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
96        let result = unsafe {
97            match pos {
98                io::SeekFrom::Start(pos) => {
99                    ffi::zip_fseek(self.handle, pos as _, ffi::SEEK_SET as _)
100                }
101                io::SeekFrom::End(pos) => ffi::zip_fseek(self.handle, pos as _, ffi::SEEK_END as _),
102                io::SeekFrom::Current(pos) => {
103                    ffi::zip_fseek(self.handle, pos as _, ffi::SEEK_CUR as _)
104                }
105            }
106        };
107        if result == -1 {
108            let error: Error = self.error().into();
109            Err(io::Error::new(io::ErrorKind::Other, error))
110        } else {
111            unsafe {
112                // Assume this will work, otherwise the fseek would have already failed.
113                Ok(ffi::zip_ftell(self.handle) as _)
114            }
115        }
116    }
117}