rustdesk/libs/portable/src/bin_reader.rs
2022-09-21 11:28:28 +08:00

135 lines
4.1 KiB
Rust

use std::{
fs::{self},
io::{Cursor, Read},
path::PathBuf,
};
const BIN_DATA: &[u8] = include_bytes!("../data.bin");
// 4bytes
const LENGTH: usize = 4;
const IDENTIFIER_LENGTH: usize = 8;
const MD5_LENGTH: usize = 32;
const BUF_SIZE: usize = 4096;
pub(crate) struct BinaryData {
pub md5_code: &'static [u8],
// compressed gzip data
pub raw: &'static [u8],
pub path: String,
}
pub(crate) struct BinaryReader {
pub files: Vec<BinaryData>,
pub exe: String,
}
impl Default for BinaryReader {
fn default() -> Self {
let (files, exe) = BinaryReader::read();
Self { files, exe }
}
}
impl BinaryData {
fn decompress(&self) -> Vec<u8> {
let cursor = Cursor::new(self.raw);
let mut decoder = brotli::Decompressor::new(cursor, BUF_SIZE);
let mut buf = Vec::new();
decoder.read_to_end(&mut buf).unwrap();
buf
}
pub fn write_to_file(&self, prefix: &PathBuf) {
let p = prefix.join(&self.path);
if let Some(parent) = p.parent() {
if !parent.exists() {
let _ = fs::create_dir_all(parent);
}
}
if p.exists() {
// check md5
let f = fs::read(p.clone()).unwrap();
let digest = format!("{:x}", md5::compute(&f));
let md5_record = String::from_utf8_lossy(self.md5_code);
if digest == md5_record {
// same, skip this file
println!("skip {}", &self.path);
return;
} else {
println!("writing {}", p.display());
println!("{} -> {}", md5_record, digest)
}
}
let _ = fs::write(p, self.decompress());
}
}
impl BinaryReader {
fn read() -> (Vec<BinaryData>, String) {
let mut base: usize = 0;
let mut parsed = vec![];
assert!(BIN_DATA.len() > IDENTIFIER_LENGTH, "bin data invalid!");
let mut iden = String::from_utf8_lossy(&BIN_DATA[base..base + IDENTIFIER_LENGTH]);
if iden != "rustdesk" {
panic!("bin file is not vaild!");
}
base += IDENTIFIER_LENGTH;
loop {
iden = String::from_utf8_lossy(&BIN_DATA[base..base + IDENTIFIER_LENGTH]);
if iden == "rustdesk" {
base += IDENTIFIER_LENGTH;
break;
}
// start reading
let mut offset = 0;
let path_length = u32::from_be_bytes([
BIN_DATA[base + offset],
BIN_DATA[base + offset + 1],
BIN_DATA[base + offset + 2],
BIN_DATA[base + offset + 3],
]) as usize;
offset += LENGTH;
let path =
String::from_utf8_lossy(&BIN_DATA[base + offset..base + offset + path_length])
.to_string();
offset += path_length;
// file sz
let file_length = u32::from_be_bytes([
BIN_DATA[base + offset],
BIN_DATA[base + offset + 1],
BIN_DATA[base + offset + 2],
BIN_DATA[base + offset + 3],
]) as usize;
offset += LENGTH;
let raw = &BIN_DATA[base + offset..base + offset + file_length];
offset += file_length;
// md5
let md5 = &BIN_DATA[base + offset..base + offset + MD5_LENGTH];
offset += MD5_LENGTH;
parsed.push(BinaryData {
md5_code: md5,
raw: raw,
path: path,
});
base += offset;
}
// executable
let executable = String::from_utf8_lossy(&BIN_DATA[base..]).to_string();
(parsed, executable)
}
#[cfg(unix)]
pub fn configure_permission(&self, prefix: &PathBuf) {
use std::os::unix::prelude::PermissionsExt;
let exe_path = prefix.join(&self.exe);
if exe_path.exists() {
let f = File::open(exe_path).unwrap();
let meta = f.metadata().unwrap();
let mut permissions = meta.permissions();
permissions.set_mode(0o755);
f.set_permissions(permissions).unwrap();
}
}
}