mirror of
https://github.com/Bayselonarrend/OpenIntegrations.git
synced 2026-06-20 09:19:27 +02:00
7z: распаковка в буфер
This commit is contained in:
Generated
+6
-6
@@ -121,14 +121,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "common-backend"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "common-core"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
dependencies = [
|
||||
"addin1c",
|
||||
"common-janx",
|
||||
@@ -136,14 +136,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "common-janx"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "common-logs"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"common-janx",
|
||||
@@ -152,7 +152,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "common-utils"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
dependencies = [
|
||||
"common-janx",
|
||||
]
|
||||
@@ -350,7 +350,7 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
|
||||
[[package]]
|
||||
name = "opi_sevenz"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
dependencies = [
|
||||
"common-backend",
|
||||
"common-core",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "opi_sevenz"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
license = "MIT"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -66,6 +66,15 @@ impl AddIn {
|
||||
.pack_from_description_to_file(description, archive_path)
|
||||
}
|
||||
|
||||
pub fn unpack_to_description(
|
||||
&mut self,
|
||||
archive_data: &[u8],
|
||||
password: &str,
|
||||
) -> Result<JanxValue, String> {
|
||||
self.lock_backend()
|
||||
.unpack_to_description(archive_data, password)
|
||||
}
|
||||
|
||||
pub fn set_logger(&mut self, logger_config: &JanxValue) -> JanxValue {
|
||||
match Logger::from_janx(logger_config) {
|
||||
Ok(logger) => match self.lock_backend().set_logger(Arc::new(logger)) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
|
||||
use common_core::{FromJanx, JanxValue};
|
||||
use common_core::{FromJanx, JanxValue, janx};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArchiveDescription {
|
||||
@@ -43,6 +44,29 @@ impl ArchiveDescription {
|
||||
|
||||
Ok(Self { password, entries })
|
||||
}
|
||||
|
||||
pub fn from_flat_entries(
|
||||
password: String,
|
||||
entries: &[(String, bool, Option<Vec<u8>>)],
|
||||
) -> Self {
|
||||
let mut tree = TreeDir::default();
|
||||
|
||||
for (path, is_directory, data) in entries {
|
||||
tree.insert(path, *is_directory, data.clone());
|
||||
}
|
||||
|
||||
Self {
|
||||
password,
|
||||
entries: tree.into_nodes(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_janx(&self) -> JanxValue {
|
||||
janx!({
|
||||
"password": self.password.clone(),
|
||||
"entries": nodes_to_janx(&self.entries),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_entries(value: &JanxValue) -> Result<Vec<ArchiveNode>, String> {
|
||||
@@ -119,3 +143,81 @@ pub fn join_archive_path(prefix: &str, name: &str) -> String {
|
||||
format!("{}/{}", prefix.trim_end_matches('/'), name)
|
||||
}
|
||||
}
|
||||
|
||||
fn nodes_to_janx(nodes: &[ArchiveNode]) -> JanxValue {
|
||||
JanxValue::Array(nodes.iter().map(node_to_janx).collect())
|
||||
}
|
||||
|
||||
fn node_to_janx(node: &ArchiveNode) -> JanxValue {
|
||||
match node {
|
||||
ArchiveNode::Directory { name, entries } => janx!({
|
||||
"name": name.clone(),
|
||||
"directory": true,
|
||||
"entries": nodes_to_janx(entries),
|
||||
}),
|
||||
ArchiveNode::FileFromPath { name, .. } => janx!({
|
||||
"name": name.clone(),
|
||||
"directory": false,
|
||||
"from_path": true,
|
||||
"path": String::new(),
|
||||
}),
|
||||
ArchiveNode::FileFromData { name, data } => janx!({
|
||||
"name": name.clone(),
|
||||
"directory": false,
|
||||
"from_path": false,
|
||||
"data": JanxValue::binary(data.clone()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct TreeDir {
|
||||
subdirs: BTreeMap<String, TreeDir>,
|
||||
files: BTreeMap<String, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl TreeDir {
|
||||
fn insert(&mut self, path: &str, is_directory: bool, data: Option<Vec<u8>>) {
|
||||
let path = path.trim_matches('/').replace('\\', "/");
|
||||
if path.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let parts: Vec<&str> = path.split('/').collect();
|
||||
self.insert_parts(&parts, is_directory, data);
|
||||
}
|
||||
|
||||
fn insert_parts(&mut self, parts: &[&str], is_directory: bool, data: Option<Vec<u8>>) {
|
||||
if parts.len() == 1 {
|
||||
if is_directory {
|
||||
self.subdirs.entry(parts[0].to_string()).or_default();
|
||||
} else {
|
||||
self.files
|
||||
.insert(parts[0].to_string(), data.unwrap_or_default());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
self.subdirs
|
||||
.entry(parts[0].to_string())
|
||||
.or_default()
|
||||
.insert_parts(&parts[1..], is_directory, data);
|
||||
}
|
||||
|
||||
fn into_nodes(self) -> Vec<ArchiveNode> {
|
||||
let mut nodes = Vec::new();
|
||||
|
||||
for (name, subdir) in self.subdirs {
|
||||
nodes.push(ArchiveNode::Directory {
|
||||
name,
|
||||
entries: subdir.into_nodes(),
|
||||
});
|
||||
}
|
||||
|
||||
for (name, data) in self.files {
|
||||
nodes.push(ArchiveNode::FileFromData { name, data });
|
||||
}
|
||||
|
||||
nodes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@ use std::fs::{self, File};
|
||||
use std::io::{Cursor, Seek, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use common_core::JanxValue;
|
||||
use sevenz_rust2::{
|
||||
compress, compress_encrypted, decompress, decompress_with_password, encoder_options::AesEncoderOptions,
|
||||
ArchiveEntry, ArchiveWriter, EncoderMethod, Password,
|
||||
ArchiveEntry, ArchiveReader, ArchiveWriter, EncoderMethod, Password,
|
||||
};
|
||||
|
||||
use crate::archive_description::{join_archive_path, ArchiveDescription, ArchiveNode};
|
||||
@@ -82,6 +83,39 @@ pub fn pack_description_to_file(
|
||||
.map_err(|error| format!("Failed to write archive file: {}", error))
|
||||
}
|
||||
|
||||
pub fn unpack_buffer_to_description(
|
||||
archive_data: &[u8],
|
||||
password: &str,
|
||||
) -> Result<JanxValue, String> {
|
||||
if archive_data.is_empty() {
|
||||
return Err("Archive data is empty".to_string());
|
||||
}
|
||||
|
||||
let mut reader = ArchiveReader::new(Cursor::new(archive_data.to_vec()), password.into())
|
||||
.map_err(|error| error.to_string())?;
|
||||
|
||||
let file_list: Vec<(String, bool)> = reader
|
||||
.archive()
|
||||
.files
|
||||
.iter()
|
||||
.map(|entry| (entry.name().to_string(), entry.is_directory()))
|
||||
.collect();
|
||||
|
||||
let mut collected = Vec::with_capacity(file_list.len());
|
||||
for (name, is_directory) in file_list {
|
||||
if is_directory {
|
||||
collected.push((name, true, None));
|
||||
} else {
|
||||
let data = reader
|
||||
.read_file(&name)
|
||||
.map_err(|error| error.to_string())?;
|
||||
collected.push((name, false, Some(data)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ArchiveDescription::from_flat_entries(password.to_string(), &collected).to_janx())
|
||||
}
|
||||
|
||||
fn push_nodes<W: Write + Seek>(
|
||||
nodes: &[ArchiveNode],
|
||||
prefix: &str,
|
||||
|
||||
@@ -102,6 +102,20 @@ impl SevenZBackend {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn unpack_to_description(
|
||||
&mut self,
|
||||
archive_data: &[u8],
|
||||
password: &str,
|
||||
) -> Result<JanxValue, String> {
|
||||
let archive_data = archive_data.to_vec();
|
||||
let password = password.to_string();
|
||||
self.call_janx(|response| WorkerCommand::UnpackToDescription {
|
||||
archive_data,
|
||||
password,
|
||||
response,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_logger(&mut self, logger: Arc<Logger>) -> Result<(), String> {
|
||||
if self.logger.is_some() {
|
||||
return Ok(());
|
||||
@@ -142,6 +156,13 @@ impl SevenZBackend {
|
||||
self.call_thread(build).and_then(|result| result)
|
||||
}
|
||||
|
||||
fn call_janx<F>(&mut self, build: F) -> Result<JanxValue, String>
|
||||
where
|
||||
F: FnOnce(Sender<Result<JanxValue, String>>) -> WorkerCommand,
|
||||
{
|
||||
self.call_thread(build).and_then(|result| result)
|
||||
}
|
||||
|
||||
fn call_result<F>(&mut self, build: F) -> Result<(), String>
|
||||
where
|
||||
F: FnOnce(Sender<Result<(), String>>) -> WorkerCommand,
|
||||
|
||||
@@ -18,6 +18,7 @@ pub const METHODS: &[&[u16]] = &[
|
||||
name!("UnpackFromBuffer"),
|
||||
name!("PackFromDescription"),
|
||||
name!("PackFromDescriptionToFile"),
|
||||
name!("UnpackToDescription"),
|
||||
name!("SetLogger"),
|
||||
name!("GetLogs"),
|
||||
name!("Version"),
|
||||
@@ -33,9 +34,10 @@ pub fn get_params_amount(num: usize) -> usize {
|
||||
3 => 3,
|
||||
4 => 1,
|
||||
5 => 2,
|
||||
6 => 1,
|
||||
6 => 2,
|
||||
7 => 1,
|
||||
8 => 0,
|
||||
8 => 1,
|
||||
9 => 0,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
@@ -47,6 +49,13 @@ fn box_blob_result(result: Result<Vec<u8>, String>) -> Box<dyn getset::ValueType
|
||||
}
|
||||
}
|
||||
|
||||
fn box_janx_result(result: Result<JanxValue, String>) -> Box<dyn getset::ValueType> {
|
||||
match result {
|
||||
Ok(value) => Box::new(value),
|
||||
Err(error) => Box::new(error),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn getset::ValueType> {
|
||||
match num {
|
||||
0 => {
|
||||
@@ -82,14 +91,19 @@ pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn
|
||||
Box::new(obj.pack_from_description_to_file(&description, &archive_path))
|
||||
}
|
||||
6 => {
|
||||
let archive_data = params[0].get_blob().unwrap_or_default().to_vec();
|
||||
let password = params[1].get_string().unwrap_or_default();
|
||||
box_janx_result(obj.unpack_to_description(&archive_data, &password))
|
||||
}
|
||||
7 => {
|
||||
let logger_config = JanxValue::from_variant(¶ms[0]);
|
||||
Box::new(obj.set_logger(&logger_config))
|
||||
}
|
||||
7 => {
|
||||
8 => {
|
||||
let count = params[0].get_i32().unwrap_or(0) as usize;
|
||||
Box::new(obj.get_logs(count))
|
||||
}
|
||||
8 => Box::new(version()),
|
||||
9 => Box::new(version()),
|
||||
_ => Box::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,11 @@ pub enum WorkerCommand {
|
||||
archive_path: String,
|
||||
response: Sender<JanxValue>,
|
||||
},
|
||||
UnpackToDescription {
|
||||
archive_data: Vec<u8>,
|
||||
password: String,
|
||||
response: Sender<Result<JanxValue, String>>,
|
||||
},
|
||||
SetLogger {
|
||||
logger: Arc<Logger>,
|
||||
response: Sender<Result<(), String>>,
|
||||
@@ -144,6 +149,15 @@ impl Session {
|
||||
Err(error) => janx_error(error),
|
||||
}
|
||||
}
|
||||
|
||||
fn unpack_to_description(
|
||||
&self,
|
||||
archive_data: &[u8],
|
||||
password: &str,
|
||||
) -> Result<JanxValue, String> {
|
||||
self.log("UnpackToDescription");
|
||||
archive_ops::unpack_buffer_to_description(archive_data, password)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn_thread(logger: Option<Arc<Logger>>) -> Result<SyncBackendThread<WorkerCommand>, String> {
|
||||
@@ -200,6 +214,14 @@ pub fn spawn_thread(logger: Option<Arc<Logger>>) -> Result<SyncBackendThread<Wor
|
||||
let result = session.pack_from_description_to_file(&description, &archive_path);
|
||||
let _ = response.send(result);
|
||||
}
|
||||
WorkerCommand::UnpackToDescription {
|
||||
archive_data,
|
||||
password,
|
||||
response,
|
||||
} => {
|
||||
let result = session.unpack_to_description(&archive_data, &password);
|
||||
let _ = response.send(result);
|
||||
}
|
||||
WorkerCommand::SetLogger { logger, response } => {
|
||||
session.logger = Some(logger);
|
||||
session.log("Logger initialized");
|
||||
|
||||
Reference in New Issue
Block a user