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