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 Ok(ffi::zip_ftell(self.handle) as _)
114 }
115 }
116 }
117}