unrar_async/open_archive/
data.rs

1use std::ffi::CString;
2use std::fmt;
3use std::path::Path;
4use std::ptr;
5
6pub(crate) struct Handle(Box<unrar_sys::Handle>);
7impl Handle {
8	pub fn from_ffi(handle: *mut unrar_sys::Handle) -> Self {
9		unsafe { Self(Box::from_raw(handle)) }
10	}
11
12	pub fn as_ffi(&self) -> *const unrar_sys::Handle {
13		&*self.0
14	}
15}
16impl fmt::Debug for Handle {
17	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18		fmt::Pointer::fmt(&self.0, f)
19	}
20}
21
22#[derive(Debug)]
23pub(crate) struct OpenArchiveData {
24	pub archive_name: CString,
25	pub open_mode: u32,
26	pub open_result: u32,
27	pub comment_buffer: Option<CString>,
28	pub comment_buffer_size: u32,
29	pub comment_state: u32
30}
31
32impl OpenArchiveData {
33	pub fn new(archive_name: CString, open_mode: u32) -> Self {
34		Self{
35			archive_name,
36			open_mode,
37			open_result: 0,
38			comment_buffer: None,
39			comment_buffer_size: 0,
40			comment_state: 0
41		}
42	}
43
44	pub fn as_ffi(&self) -> unrar_sys::OpenArchiveData {
45		unrar_sys::OpenArchiveData{
46			archive_name: self.archive_name.as_ptr(),
47			open_mode: self.open_mode,
48			open_result: self.open_result,
49			comment_buffer: self.comment_buffer.as_ref().map(|s| s.as_ptr() as *mut _).unwrap_or(ptr::null_mut()),
50			comment_buffer_size: self.comment_buffer_size,
51			comment_size: self.comment_buffer.as_ref().map(|s| s.to_bytes().len() as u32).unwrap_or(0),
52			comment_state: self.comment_state
53		}
54	}
55}
56
57/*
58impl<'a> Drop for OpenArchiveData<'a> {
59	fn drop(&mut self) {
60		self.comment_buffer.into_raw();
61	}
62}
63*/
64
65pub(crate) struct HeaderData(unrar_sys::HeaderData);
66
67impl HeaderData {
68	fn inner(&self) -> &unrar_sys::HeaderData {
69		&self.0
70	}
71}
72
73impl Default for HeaderData {
74	fn default() -> Self {
75		Self(unrar_sys::HeaderData{
76			archive_name: [0; 260],
77			filename: [0; 260],
78			flags: 0,
79			pack_size: 0,
80			unp_size: 0,
81			host_os: 0,
82			file_crc: 0,
83			file_time: 0,
84			unp_ver: 0,
85			method: 0,
86			file_attr: 0,
87			comment_buffer: ptr::null_mut(),
88			comment_buffer_size: 0,
89			comment_size: 0,
90			comment_state: 0
91		})
92	}
93}
94
95// SAFETY:  comment_buffer is the only !Send field, because it's a raw pointer; that pointer is
96// always strictly null.
97#[allow(clippy::non_send_fields_in_send_ty)]
98unsafe impl Send for HeaderData {}
99
100/// A single entry contained in an archive - usually, a file or directory
101#[derive(Debug)]
102pub struct Entry {
103	pub filename: String,
104	pub flags: Flags,
105	pub unpacked_size: u32,
106	pub file_crc: u32,
107	pub file_time: u32,
108	pub method: u32,
109	pub file_attr: u32,
110	pub next_volume: Option<String>
111}
112
113impl Entry {
114	/// Whether or not an entry is split across multiple volumes in a multi-part archive
115	#[inline]
116	pub fn is_split(&self) -> bool {
117		self.flags.contains(Flags::SPLIT_BEFORE) || self.flags.contains(Flags::SPLIT_AFTER)
118	}
119
120	#[inline]
121	pub fn is_directory(&self) -> bool {
122		self.flags.contains(Flags::DIRECTORY)
123	}
124
125	#[inline]
126	pub fn is_encrypted(&self) -> bool {
127		self.flags.contains(Flags::ENCRYPTED)
128	}
129
130	#[inline]
131	pub fn is_file(&self) -> bool {
132		!self.is_directory()
133	}
134}
135
136impl AsRef<Path> for Entry {
137	#[inline]
138	fn as_ref(&self) -> &Path {
139		self.filename.as_ref()
140	}
141}
142
143impl fmt::Display for Entry {
144	#[inline]
145	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146		f.write_str(&self.filename)?;
147		if(self.is_directory()) {
148			f.write_str("/")?;
149		}
150		if(self.is_split()) {
151			f.write_str(" (partial)")?;
152		}
153		Ok(())
154	}
155}
156
157impl TryFrom<HeaderData> for Entry {
158	type Error = std::string::FromUtf8Error;
159	fn try_from(header: HeaderData) -> Result<Self, Self::Error> {
160		let inner = header.inner();
161		let filename_len = unsafe { libc::strlen(&inner.filename as *const _) };
162		let filename = inner.filename[..filename_len]
163			.iter()
164			.map(|&c| c as u8)
165			.collect::<Vec<_>>();
166		Ok(Self{
167			filename: String::from_utf8(filename)?,
168			flags: Flags::from_bits(inner.flags).unwrap(),
169			unpacked_size: inner.unp_size,
170			file_crc: inner.file_crc,
171			file_time: inner.file_time,
172			method: inner.method,
173			file_attr: inner.file_attr,
174			next_volume: None
175		})
176	}
177}
178
179bitflags::bitflags! {
180	#[derive(Debug)]
181	pub struct Flags: u32 {
182		const SPLIT_BEFORE = 0x01;
183		const SPLIT_AFTER = 0x02;
184		const ENCRYPTED = 0x04;
185		//const RESERVED = 0x08;
186		const SOLID = 0x10;
187		const DIRECTORY = 0x20;
188	}
189}
190