styles: 更改一些样式
This commit is contained in:
parent
142a8cd3eb
commit
a279a262b7
22
src-tauri/Cargo.lock
generated
22
src-tauri/Cargo.lock
generated
@ -1913,13 +1913,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "memmap"
|
||||
version = "0.7.0"
|
||||
name = "memmap2"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
||||
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2063,7 +2062,7 @@ version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
|
||||
dependencies = [
|
||||
"proc-macro-crate 1.3.1",
|
||||
"proc-macro-crate 3.2.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.90",
|
||||
@ -2409,16 +2408,6 @@ version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
|
||||
|
||||
[[package]]
|
||||
name = "pe_serialize_proc_macro"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
@ -3773,8 +3762,7 @@ name = "test-tauri"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"memmap",
|
||||
"pe_serialize_proc_macro",
|
||||
"memmap2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
|
@ -18,9 +18,8 @@ name = "test_tauri_lib"
|
||||
tauri-build = {version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
bitflags = "2.6.0"
|
||||
memmap = "0.7.0"
|
||||
pe_serialize_proc_macro = {path = "./pe_serialize_proc_macro"}
|
||||
bitflags = {version= "2.6.0", features = ["serde"] }
|
||||
memmap2 = "0.9.5"
|
||||
serde = {version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tauri = {version = "2", features = [] }
|
||||
|
1
src-tauri/pe_serialize_proc_macro/.gitignore
vendored
1
src-tauri/pe_serialize_proc_macro/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/target/
|
68
src-tauri/pe_serialize_proc_macro/Cargo.lock
generated
68
src-tauri/pe_serialize_proc_macro/Cargo.lock
generated
@ -1,68 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "pe_serialize_proc_macro"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
@ -1,16 +0,0 @@
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[package]
|
||||
name = "pe_serialize_proc_macro"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0.92"
|
||||
quote = "1.0.37"
|
||||
serde = "1.0.215"
|
||||
syn = "2.0.90"
|
||||
|
||||
[serde.features]
|
||||
default = ["derive"]
|
@ -1,85 +0,0 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::Data;
|
||||
|
||||
fn impl_serialize_ex(ast: &syn::DeriveInput) -> TokenStream {
|
||||
let name = &ast.ident;
|
||||
let fields = match ast.data {
|
||||
Data::Struct(ref data) => &data.fields,
|
||||
_ => panic!("CustomSerialize 只能用于结构体!"),
|
||||
};
|
||||
let field_len = fields.len();
|
||||
// 迭代器,为每一个字段实现serialize_field
|
||||
let serialize_fields = match fields {
|
||||
syn::Fields::Named(ref fields) => {
|
||||
fields.named.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
let ty = &f.ty;
|
||||
let mut child_token_stream = proc_macro2::TokenStream::new();
|
||||
// 如果字段是数组类型
|
||||
if let syn::Type::Array(ref array) = ty {
|
||||
let len = &array.len;
|
||||
let child_ty = &array.elem;
|
||||
// 类型所占字节
|
||||
|
||||
child_token_stream = quote! {
|
||||
children = Some(Vec::new());
|
||||
let field_size = std::mem::size_of::<#child_ty>();
|
||||
for i in 0..#len {
|
||||
let child_value = serde_json::json!({
|
||||
"name": format!("{}[{}]", stringify!(#name), i),
|
||||
"value": format!("0x{:0width$X}",self.#name[i], width=field_size),
|
||||
"field_type": stringify!(#child_ty),
|
||||
"size": field_size,
|
||||
"offset": (&self.#name[i] as *const _ as usize) - (self as *const _ as usize),
|
||||
"children": null
|
||||
});
|
||||
children.as_mut().unwrap().push(child_value);
|
||||
}
|
||||
};
|
||||
}else{
|
||||
child_token_stream = quote! {
|
||||
let field_size = std::mem::size_of::<#ty>();
|
||||
value = serde_json::json!(format!("0x{:0width$X}",&self.#name, width=field_size));
|
||||
};
|
||||
}
|
||||
quote! {
|
||||
let mut value = serde_json::Value::Null;
|
||||
let mut children: Option<Vec<serde_json::Value>> = None;
|
||||
#child_token_stream
|
||||
|
||||
let json_value = serde_json::json!({
|
||||
"name": stringify!(#name),
|
||||
"value": value,
|
||||
"field_type": stringify!(#ty),
|
||||
"size": std::mem::size_of::<#ty>(),
|
||||
"offset": (&self.#name as *const _ as usize) - (self as *const _ as usize),
|
||||
"children": &children
|
||||
});
|
||||
state.serialize_field(stringify!(#name), &json_value)?;
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => panic!("CustomSerialize 只能用于结构体!"),
|
||||
};
|
||||
|
||||
let gen = quote! {
|
||||
impl serde::Serialize for #name {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer {
|
||||
let mut state = serializer.serialize_struct(stringify!(#name), #field_len)?;
|
||||
#(#serialize_fields)*
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
};
|
||||
gen.into()
|
||||
}
|
||||
|
||||
// 拓展Serialize
|
||||
#[proc_macro_derive(SerializeEX)]
|
||||
pub fn serialize_ex(input: TokenStream) -> TokenStream {
|
||||
let ast = syn::parse(input).unwrap();
|
||||
impl_serialize_ex(&ast)
|
||||
}
|
@ -1,21 +1,10 @@
|
||||
use crate::{
|
||||
app_error::AppError,
|
||||
pe_parse::{header::ImageDosHeader, pe::PE},
|
||||
services::{self, GLOBAL_FILE_DATA},
|
||||
services::{self, file::{get_nt_headers_data, ResponseDOSHeaderData, ResponseFileHeaderData, ResponseNTHeaderData}, GLOBAL_FILE_DATA},
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
#[tauri::command]
|
||||
pub fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
}
|
||||
|
||||
macro_rules! offset_of {
|
||||
($base:expr, $field:ident) => {
|
||||
(&$base.$field as *const _ as usize) - ($base as *const _ as usize)
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct PeNodeTreeData {
|
||||
title: String,
|
||||
@ -89,21 +78,29 @@ pub fn command_open_file(file_path: &str) -> Result<(), AppError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Serialize, Default)]
|
||||
pub struct ResponseDOSHeaderData {
|
||||
name: String,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
field_type: String,
|
||||
value: Option<String>,
|
||||
children: Option<Vec<ResponseDOSHeaderData>>,
|
||||
}
|
||||
|
||||
// 命令,获取DOS头数据
|
||||
#[tauri::command]
|
||||
pub fn command_get_pe_data_dos_header() -> Result<ImageDosHeader, AppError> {
|
||||
pub fn command_get_pe_data_dos_header() -> Result<ResponseDOSHeaderData, AppError> {
|
||||
let binding = GLOBAL_FILE_DATA.lock().unwrap();
|
||||
let file_data = binding.as_ref().unwrap();
|
||||
let dos_header = file_data.get_dos_header()?;
|
||||
Ok(dos_header.clone())
|
||||
let result = ResponseDOSHeaderData {
|
||||
image_dos_header: dos_header.clone(),
|
||||
base_offset: 0,
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// 命令,获取NT头数据
|
||||
#[tauri::command]
|
||||
pub fn command_get_pe_data_nt_header() -> Result<ResponseNTHeaderData, AppError> {
|
||||
let result = get_nt_headers_data()?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// 命令,获取文件头数据
|
||||
#[tauri::command]
|
||||
pub fn command_get_pe_data_file_header() -> Result<ResponseFileHeaderData, AppError> {
|
||||
let result = services::file::get_file_header_data()?;
|
||||
Ok(result)
|
||||
}
|
@ -13,6 +13,8 @@ pub fn run() {
|
||||
commands::command_open_file,
|
||||
commands::command_get_file_pe_node_tree_data,
|
||||
commands::command_get_pe_data_dos_header,
|
||||
commands::command_get_pe_data_nt_header,
|
||||
commands::command_get_pe_data_file_header,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
@ -1,10 +1,9 @@
|
||||
use super::types::*;
|
||||
use bitflags::bitflags;
|
||||
use pe_serialize_proc_macro::SerializeEX;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::Serialize;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, SerializeEX)]
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
pub struct ImageDosHeader {
|
||||
pub e_magic: u16, // Magic number 固定值 0x5A4D
|
||||
pub e_cblp: u16,
|
||||
@ -24,10 +23,11 @@ pub struct ImageDosHeader {
|
||||
pub e_oemid: u16,
|
||||
pub e_oeminfo: u16,
|
||||
pub e_res2: [u16; 10],
|
||||
pub e_lfanew: u32, // File address of new exe header nt头的偏移
|
||||
pub e_lfanew: Offset, // File address of new exe header nt头的偏移
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
pub struct ImageNTHeaders32 {
|
||||
pub signature: u32,
|
||||
pub file_header: ImageFileHeader,
|
||||
@ -35,6 +35,7 @@ pub struct ImageNTHeaders32 {
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
pub struct ImageFileHeader {
|
||||
pub machine: u16,
|
||||
pub number_of_sections: u16,
|
||||
@ -46,6 +47,7 @@ pub struct ImageFileHeader {
|
||||
}
|
||||
bitflags! {
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
pub struct FileCharacteristics: u16 {
|
||||
const RELOCS_STRIPPED = 0x0001;
|
||||
const EXECUTABLE_IMAGE = 0x0002;
|
||||
@ -64,6 +66,7 @@ bitflags! {
|
||||
const BYTES_REVERSED_HI = 0x8000;
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
pub struct DLLCharacteristics: u16 {
|
||||
const RESERVED1 = 0x0001;
|
||||
const RESERVED2 = 0x0002;
|
||||
@ -83,6 +86,7 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
pub struct ImageOptionalHeader32 {
|
||||
pub magic: u16,
|
||||
pub major_linker_version: u8,
|
||||
|
@ -32,4 +32,49 @@ pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + Sized {
|
||||
let result = self.get_mut::<ImageDosHeader>(0)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Get the NT headers without verifying its contents.
|
||||
fn get_nt_headers(&self) -> Result<&ImageNTHeaders32, PEParseError> {
|
||||
let nt_offset = self.get_nt_headers_offset()?;
|
||||
let result = self.get_ref::<ImageNTHeaders32>(nt_offset)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// 获取nt头的偏移
|
||||
fn get_nt_headers_offset(&self) -> Result<usize, PEParseError> {
|
||||
let dos_header = self.get_dos_header()?;
|
||||
let nt_offset = dos_header.e_lfanew.0 as usize;
|
||||
Ok(nt_offset)
|
||||
}
|
||||
|
||||
/// Get the NT headers without mutating its contents.
|
||||
fn get_nt_headers_mut(&mut self) -> Result<&mut ImageNTHeaders32, PEParseError> {
|
||||
let nt_offset = self.get_nt_headers_offset()?;
|
||||
let result = self.get_mut::<ImageNTHeaders32>(nt_offset)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// 获取文件头的偏移
|
||||
fn get_file_header_offset(&self) -> Result<usize, PEParseError> {
|
||||
// 1. 获取nt头偏移
|
||||
let nt_offset = self.get_nt_headers_offset()?;
|
||||
// 2. 计算文件头偏移
|
||||
let file_header_offset = nt_offset + std::mem::size_of::<u32>();
|
||||
Ok(file_header_offset)
|
||||
}
|
||||
|
||||
// 获取文件头数据
|
||||
fn get_file_header(&self) -> Result<&ImageFileHeader, PEParseError> {
|
||||
let file_header_offset = self.get_file_header_offset()?;
|
||||
let result = self.get_ref::<ImageFileHeader>(file_header_offset)?;
|
||||
Ok(result)
|
||||
}
|
||||
// 获取文件头数据
|
||||
fn get_file_header_mut(&mut self) -> Result<&mut ImageFileHeader, PEParseError> {
|
||||
let file_header_offset = self.get_file_header_offset()?;
|
||||
let result = self.get_mut::<ImageFileHeader>(file_header_offset)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,18 @@
|
||||
use std::fmt::{Formatter, UpperHex};
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
pub struct Offset(pub u32);
|
||||
|
||||
impl UpperHex for Offset {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
pub struct RVA(pub u32);
|
||||
|
@ -1,4 +1,9 @@
|
||||
use memmap::*;
|
||||
use memmap2::*;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{app_error::AppError, pe_parse::{header::{ImageDosHeader, ImageFileHeader, ImageNTHeaders32}, pe::PE}};
|
||||
|
||||
use super::GLOBAL_FILE_DATA;
|
||||
|
||||
// TODO: 打开文件,并将文件映射到内存
|
||||
pub fn mmap_mut_file(file_path: &str) -> Result<Mmap, std::io::Error> {
|
||||
@ -10,3 +15,47 @@ pub fn mmap_mut_file(file_path: &str) -> Result<Mmap, std::io::Error> {
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ResponseDOSHeaderData {
|
||||
pub image_dos_header: ImageDosHeader,
|
||||
pub base_offset: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ResponseNTHeaderData {
|
||||
image_nt_header: ImageNTHeaders32,
|
||||
base_offset: usize,
|
||||
}
|
||||
|
||||
pub fn get_nt_headers_data() -> Result<ResponseNTHeaderData, AppError> {
|
||||
let binding = GLOBAL_FILE_DATA.lock().unwrap();
|
||||
let file_data = binding.as_ref().unwrap();
|
||||
let nt_header = file_data.get_nt_headers()?;
|
||||
let nt_offset = file_data.get_nt_headers_offset()?;
|
||||
let result = ResponseNTHeaderData {
|
||||
image_nt_header: nt_header.clone(),
|
||||
base_offset: nt_offset,
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// 获取文件头数据
|
||||
#[derive(Serialize)]
|
||||
pub struct ResponseFileHeaderData {
|
||||
pub file_header: ImageFileHeader,
|
||||
pub base_offset: usize,
|
||||
}
|
||||
|
||||
pub fn get_file_header_data() -> Result<ResponseFileHeaderData, AppError> {
|
||||
let binding = GLOBAL_FILE_DATA.lock().unwrap();
|
||||
let file_data = binding.as_ref().unwrap();
|
||||
let file_header = file_data.get_file_header()?;
|
||||
let file_header_offset = file_data.get_file_header_offset()?;
|
||||
let result = ResponseFileHeaderData {
|
||||
file_header: file_header.clone(),
|
||||
base_offset: file_header_offset,
|
||||
};
|
||||
Ok(result)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use memmap::{Mmap, MmapMut};
|
||||
use memmap2::{Mmap, MmapMut};
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Mutex,
|
||||
|
@ -5,4 +5,5 @@
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
padding: 16px;
|
||||
overflow: scroll;
|
||||
}
|
@ -3,11 +3,207 @@ import { Flex } from "antd";
|
||||
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import type { GetRef, InputRef, TableProps } from "antd";
|
||||
import { Form, Input, Table } from "antd";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
|
||||
type FormInstance<T> = GetRef<typeof Form<T>>;
|
||||
|
||||
const EditableContext = React.createContext<FormInstance<any> | null>(null);
|
||||
|
||||
interface DosHeaderFieldProps {
|
||||
name: string;
|
||||
value: number | [number];
|
||||
size: number;
|
||||
offset: number;
|
||||
field_type: string;
|
||||
}
|
||||
|
||||
interface DosHeaderResponse {
|
||||
image_dos_header: DosHeaderFieldResponse;
|
||||
base_offset: number;
|
||||
}
|
||||
|
||||
interface DosHeaderFieldResponse {
|
||||
e_magic: number;
|
||||
e_cblp: number;
|
||||
e_cp: number;
|
||||
e_crlc: number;
|
||||
e_cparhdr: number;
|
||||
e_minalloc: number;
|
||||
e_maxalloc: number;
|
||||
e_ss: number;
|
||||
e_sp: number;
|
||||
e_csum: number;
|
||||
e_ip: number;
|
||||
e_cs: number;
|
||||
e_lfarlc: number;
|
||||
e_ovno: number;
|
||||
e_res: number;
|
||||
e_oemid: number;
|
||||
e_oeminfo: number;
|
||||
e_res2: number;
|
||||
e_lfanew: number;
|
||||
}
|
||||
|
||||
// 定义DOS Header的数据结构
|
||||
interface IDosHeader {
|
||||
e_magic: DosHeaderFieldProps;
|
||||
e_cblp: DosHeaderFieldProps;
|
||||
e_cp: DosHeaderFieldProps;
|
||||
e_crlc: DosHeaderFieldProps;
|
||||
e_cparhdr: DosHeaderFieldProps;
|
||||
e_minalloc: DosHeaderFieldProps;
|
||||
e_maxalloc: DosHeaderFieldProps;
|
||||
e_ss: DosHeaderFieldProps;
|
||||
e_sp: DosHeaderFieldProps;
|
||||
e_csum: DosHeaderFieldProps;
|
||||
e_ip: DosHeaderFieldProps;
|
||||
e_cs: DosHeaderFieldProps;
|
||||
e_lfarlc: DosHeaderFieldProps;
|
||||
e_ovno: DosHeaderFieldProps;
|
||||
e_res: DosHeaderFieldProps;
|
||||
e_oemid: DosHeaderFieldProps;
|
||||
e_oeminfo: DosHeaderFieldProps;
|
||||
e_res2: DosHeaderFieldProps;
|
||||
e_lfanew: DosHeaderFieldProps;
|
||||
}
|
||||
|
||||
const templateData: IDosHeader = {
|
||||
e_magic: {
|
||||
name: "e_magic",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 0,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_cblp: {
|
||||
name: "e_cblp",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 2,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_cp: {
|
||||
name: "e_cp",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 4,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_crlc: {
|
||||
name: "e_crlc",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 6,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_cparhdr: {
|
||||
name: "e_cparhdr",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 8,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_minalloc: {
|
||||
name: "e_minalloc",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 10,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_maxalloc: {
|
||||
name: "e_maxalloc",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 12,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_ss: {
|
||||
name: "e_ss",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 14,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_sp: {
|
||||
name: "e_sp",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 16,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_csum: {
|
||||
name: "e_csum",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 18,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_ip: {
|
||||
name: "e_ip",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 20,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_cs: {
|
||||
name: "e_cs",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 22,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_lfarlc: {
|
||||
name: "e_lfarlc",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 24,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_ovno: {
|
||||
name: "e_ovno",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 26,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_res: {
|
||||
name: "e_res",
|
||||
value: null,
|
||||
size: 8,
|
||||
offset: 28,
|
||||
field_type: "[WORD; 4]",
|
||||
},
|
||||
e_oemid: {
|
||||
name: "e_oemid",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 36,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_oeminfo: {
|
||||
name: "e_oeminfo",
|
||||
value: 0,
|
||||
size: 2,
|
||||
offset: 38,
|
||||
field_type: "WORD",
|
||||
},
|
||||
e_res2: {
|
||||
name: "e_res2",
|
||||
value: 0,
|
||||
size: 20,
|
||||
offset: 40,
|
||||
field_type: "[WORD; 10]",
|
||||
},
|
||||
e_lfanew: {
|
||||
name: "e_lfanew",
|
||||
value: 0,
|
||||
size: 4,
|
||||
offset: 60,
|
||||
field_type: "DWORD",
|
||||
},
|
||||
};
|
||||
|
||||
interface Item {
|
||||
name: string; // 字段名称
|
||||
offset: string; // 偏移
|
||||
@ -109,16 +305,47 @@ interface DataType {
|
||||
|
||||
type ColumnTypes = Exclude<TableProps<DataType>["columns"], undefined>;
|
||||
|
||||
const App = ({ defaultData = [] }) => {
|
||||
const [dataSource, setDataSource] = useState<DataType[]>(defaultData);
|
||||
useEffect(()=>{
|
||||
setDataSource(defaultData)
|
||||
}, [defaultData])
|
||||
const App = () => {
|
||||
const [offsetHex, setOffsetHex] = useState(false);
|
||||
const [dataSource, setDataSource] = useState<DataType[]>([]);
|
||||
|
||||
const defaultColumns: (ColumnTypes[number] & {
|
||||
editable?: boolean;
|
||||
dataIndex: string;
|
||||
})[] = [
|
||||
useEffect(() => {
|
||||
invoke("command_get_pe_data_dos_header").then(
|
||||
(resData: DosHeaderResponse) => {
|
||||
console.log("resData", resData);
|
||||
// 格式化数据
|
||||
let data = cloneDeep(templateData); // 先clone一个模板
|
||||
let base_offset = resData.base_offset;
|
||||
Object.keys(resData.image_dos_header).forEach((key) => {
|
||||
let value = resData.image_dos_header[key];
|
||||
data[key].offset = base_offset + data[key].offset;
|
||||
if (Array.isArray(value)) {
|
||||
// 如果是数组
|
||||
data[key].children = value.map((item, index) => {
|
||||
let child_size = data[key].size / value.length;
|
||||
const extractWord = (input) => {
|
||||
const match = input.match(/\[([\w]+);/);
|
||||
return match ? match[1] : null; // 如果匹配到,返回结果;否则返回 null
|
||||
};
|
||||
return {
|
||||
name: `${key}[${index}]`,
|
||||
offset: index * child_size + data[key].offset,
|
||||
size: child_size,
|
||||
value: "0x" + item.toString(16).padStart(4, "0").toUpperCase(),
|
||||
field_type: extractWord(data[key].field_type),
|
||||
};
|
||||
});
|
||||
} else {
|
||||
data[key].value =
|
||||
"0x" + value.toString(16).padStart(4, "0").toUpperCase();
|
||||
}
|
||||
});
|
||||
setDataSource(Object.values(data));
|
||||
}
|
||||
);
|
||||
}, []);
|
||||
|
||||
const defaultColumns = [
|
||||
{
|
||||
title: "字段名称",
|
||||
dataIndex: "name",
|
||||
@ -127,6 +354,15 @@ const App = ({ defaultData = [] }) => {
|
||||
{
|
||||
title: "偏移量",
|
||||
dataIndex: "offset",
|
||||
defaultSortOrder: "ascend",
|
||||
render: (text) => {
|
||||
return offsetHex ? `0x${text.toString(16).toUpperCase()}` : text;
|
||||
},
|
||||
onHeaderCell: (column) => ({
|
||||
onClick: () => {
|
||||
setOffsetHex(!offsetHex);
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
title: "字段类型",
|
||||
@ -202,15 +438,16 @@ const App = ({ defaultData = [] }) => {
|
||||
columns={columns as ColumnTypes}
|
||||
pagination={false}
|
||||
size="small"
|
||||
sticky={{ offsetHeader: -16 }}
|
||||
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default function DosHeader({ defaultData }) {
|
||||
console.log("DosHeader defaultData:", defaultData);
|
||||
export default function DosHeader() {
|
||||
return (
|
||||
<Flex className={styles.root}>
|
||||
<App defaultData={defaultData} />
|
||||
<App />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
9
src/components/FileHeader/FileHeader.module.scss
Normal file
9
src/components/FileHeader/FileHeader.module.scss
Normal file
@ -0,0 +1,9 @@
|
||||
.root {
|
||||
margin: 8px;
|
||||
margin-top: 0;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
padding: 16px;
|
||||
overflow: scroll;
|
||||
}
|
247
src/components/FileHeader/FileHeader.tsx
Normal file
247
src/components/FileHeader/FileHeader.tsx
Normal file
@ -0,0 +1,247 @@
|
||||
import { Flex, Form, FormInstance, Input, Table } from "antd";
|
||||
import styles from "./FileHeader.module.scss";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import React from "react";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
const EditableContext = React.createContext<FormInstance<any> | null>(null);
|
||||
|
||||
const templateData = {
|
||||
machine: {
|
||||
name: "Machine",
|
||||
offset: 0,
|
||||
size: 2,
|
||||
value: null,
|
||||
field_type: "WORD",
|
||||
},
|
||||
number_of_sections: {
|
||||
name: "Number of Sections",
|
||||
offset: 2,
|
||||
size: 2,
|
||||
value: null,
|
||||
field_type: "WORD",
|
||||
},
|
||||
time_date_stamp: {
|
||||
name: "Time Date Stamp",
|
||||
offset: 4,
|
||||
size: 4,
|
||||
value: null,
|
||||
field_type: "DWORD",
|
||||
},
|
||||
pointer_to_symbol_table: {
|
||||
name: "Pointer to Symbol Table",
|
||||
offset: 8,
|
||||
size: 4,
|
||||
value: null,
|
||||
field_type: "DWORD",
|
||||
},
|
||||
number_of_symbols: {
|
||||
name: "Number of Symbols",
|
||||
offset: 12,
|
||||
size: 4,
|
||||
value: null,
|
||||
field_type: "DWORD",
|
||||
},
|
||||
size_of_optional_header: {
|
||||
name: "Size of Optional Header",
|
||||
offset: 16,
|
||||
size: 2,
|
||||
value: null,
|
||||
field_type: "WORD",
|
||||
},
|
||||
characteristics: {
|
||||
name: "Characteristics",
|
||||
offset: 18,
|
||||
size: 2,
|
||||
value: null,
|
||||
field_type: "WORD",
|
||||
},
|
||||
};
|
||||
|
||||
const EditableRow = ({ index, ...props }) => {
|
||||
const [form] = Form.useForm();
|
||||
return (
|
||||
<Form form={form} component={false}>
|
||||
<EditableContext.Provider value={form}>
|
||||
<tr {...props} />
|
||||
</EditableContext.Provider>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
const EditableCell = ({
|
||||
title,
|
||||
editable,
|
||||
children,
|
||||
dataIndex,
|
||||
record,
|
||||
handleSave,
|
||||
...restProps
|
||||
}) => {
|
||||
const [editing, setEditing] = useState(false);
|
||||
const inputRef = useRef(null);
|
||||
const form = useContext(EditableContext)!;
|
||||
|
||||
useEffect(() => {
|
||||
if (editing) {
|
||||
inputRef.current?.focus();
|
||||
}
|
||||
}, [editing]);
|
||||
|
||||
const toggleEdit = () => {
|
||||
setEditing(!editing);
|
||||
form.setFieldsValue({ [dataIndex]: record[dataIndex] });
|
||||
};
|
||||
|
||||
const save = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
toggleEdit();
|
||||
handleSave({ ...record, ...values });
|
||||
} catch (errInfo) {
|
||||
console.log("Save failed:", errInfo);
|
||||
}
|
||||
};
|
||||
|
||||
let childNode = children;
|
||||
|
||||
if (editable) {
|
||||
childNode = editing ? (
|
||||
<Form.Item
|
||||
style={{ margin: 0 }}
|
||||
name={dataIndex}
|
||||
rules={[{ required: true, message: `${title} is required.` }]}
|
||||
>
|
||||
<Input size="small" ref={inputRef} onPressEnter={save} onBlur={save} />
|
||||
</Form.Item>
|
||||
) : (
|
||||
<div
|
||||
className="editable-cell-value-wrap"
|
||||
style={{ paddingInlineEnd: 24 }}
|
||||
onClick={toggleEdit}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <td {...restProps}>{childNode}</td>;
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
const [offsetHex, setOffsetHex] = useState(false);
|
||||
const [dataSource, setDataSource] = useState([]);
|
||||
useEffect(() => {
|
||||
invoke("command_get_pe_data_file_header").then((resData: any) => {
|
||||
console.log("resData", resData);
|
||||
let data = cloneDeep(templateData);
|
||||
let base_offset = resData.base_offset;
|
||||
Object.keys(data).forEach((key) => {
|
||||
data[key].value = resData.file_header[key];
|
||||
data[key].offset = base_offset + data[key].offset;
|
||||
});
|
||||
setDataSource(Object.values(data));
|
||||
});
|
||||
}, []);
|
||||
|
||||
const defaultColumns = [
|
||||
{
|
||||
title: "字段名称",
|
||||
dataIndex: "name",
|
||||
width: "30%",
|
||||
},
|
||||
{
|
||||
title: "偏移量",
|
||||
dataIndex: "offset",
|
||||
defaultSortOrder: "ascend",
|
||||
render: (text) => {
|
||||
return offsetHex ? `0x${text.toString(16).toUpperCase()}` : text;
|
||||
},
|
||||
onHeaderCell: (column) => ({
|
||||
onClick: () => {
|
||||
setOffsetHex(!offsetHex);
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: "字段类型",
|
||||
dataIndex: "field_type",
|
||||
},
|
||||
{
|
||||
title: "字段大小",
|
||||
dataIndex: "size",
|
||||
},
|
||||
{
|
||||
title: "字段值",
|
||||
dataIndex: "value",
|
||||
editable: true,
|
||||
},
|
||||
];
|
||||
|
||||
const replaceNodeByName = (data, name, newNode) => {
|
||||
return data.map((item) => {
|
||||
if (item.name === name) {
|
||||
return newNode;
|
||||
}
|
||||
if (item.children) {
|
||||
return {
|
||||
...item,
|
||||
children: replaceNodeByName(item.children, name, newNode),
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
};
|
||||
|
||||
const handleSave = (row) => {
|
||||
let newData = [...dataSource];
|
||||
newData = replaceNodeByName(newData, row.name, row);
|
||||
setDataSource(newData);
|
||||
};
|
||||
|
||||
const components = {
|
||||
body: {
|
||||
row: EditableRow,
|
||||
cell: EditableCell,
|
||||
},
|
||||
};
|
||||
|
||||
const columns = defaultColumns.map((col) => {
|
||||
if (!col.editable) {
|
||||
return col;
|
||||
}
|
||||
return {
|
||||
...col,
|
||||
onCell: (record) => ({
|
||||
record,
|
||||
editable: col.editable,
|
||||
dataIndex: col.dataIndex,
|
||||
title: col.title,
|
||||
handleSave,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Table
|
||||
components={components}
|
||||
rowClassName={() => "editable-row"}
|
||||
bordered
|
||||
rowKey={(record) => record.name}
|
||||
style={{ width: "100%" }}
|
||||
dataSource={dataSource}
|
||||
columns={columns as any}
|
||||
pagination={false}
|
||||
size="small"
|
||||
sticky={{ offsetHeader: -16 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default function FileHeader() {
|
||||
return (
|
||||
<Flex className={styles.root}>
|
||||
<App />
|
||||
</Flex>
|
||||
);
|
||||
}
|
8
src/components/NTHeader/NTHeader.module.scss
Normal file
8
src/components/NTHeader/NTHeader.module.scss
Normal file
@ -0,0 +1,8 @@
|
||||
.root {
|
||||
margin: 8px;
|
||||
margin-top: 0;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
padding: 16px;
|
||||
}
|
205
src/components/NTHeader/NTHeader.tsx
Normal file
205
src/components/NTHeader/NTHeader.tsx
Normal file
@ -0,0 +1,205 @@
|
||||
import { Flex, Form, FormInstance, Input, Table } from "antd";
|
||||
import styles from "./NTHeader.module.scss";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import React from "react";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
const EditableContext = React.createContext<FormInstance<any> | null>(null);
|
||||
|
||||
const templateData = {
|
||||
signature: {
|
||||
name: "Signature",
|
||||
offset: 0,
|
||||
size: 4,
|
||||
value: null,
|
||||
field_type: "DWORD",
|
||||
},
|
||||
};
|
||||
|
||||
const EditableRow = ({ index, ...props }) => {
|
||||
const [form] = Form.useForm();
|
||||
return (
|
||||
<Form form={form} component={false}>
|
||||
<EditableContext.Provider value={form}>
|
||||
<tr {...props} />
|
||||
</EditableContext.Provider>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
const EditableCell = ({
|
||||
title,
|
||||
editable,
|
||||
children,
|
||||
dataIndex,
|
||||
record,
|
||||
handleSave,
|
||||
...restProps
|
||||
}) => {
|
||||
const [editing, setEditing] = useState(false);
|
||||
const inputRef = useRef(null);
|
||||
const form = useContext(EditableContext)!;
|
||||
|
||||
useEffect(() => {
|
||||
if (editing) {
|
||||
inputRef.current?.focus();
|
||||
}
|
||||
}, [editing]);
|
||||
|
||||
const toggleEdit = () => {
|
||||
setEditing(!editing);
|
||||
form.setFieldsValue({ [dataIndex]: record[dataIndex] });
|
||||
};
|
||||
|
||||
const save = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
toggleEdit();
|
||||
handleSave({ ...record, ...values });
|
||||
} catch (errInfo) {
|
||||
console.log("Save failed:", errInfo);
|
||||
}
|
||||
};
|
||||
|
||||
let childNode = children;
|
||||
|
||||
if (editable) {
|
||||
childNode = editing ? (
|
||||
<Form.Item
|
||||
style={{ margin: 0 }}
|
||||
name={dataIndex}
|
||||
rules={[{ required: true, message: `${title} is required.` }]}
|
||||
>
|
||||
<Input size="small" ref={inputRef} onPressEnter={save} onBlur={save} />
|
||||
</Form.Item>
|
||||
) : (
|
||||
<div
|
||||
className="editable-cell-value-wrap"
|
||||
style={{ paddingInlineEnd: 24 }}
|
||||
onClick={toggleEdit}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <td {...restProps}>{childNode}</td>;
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
const [offsetHex, setOffsetHex] = useState(false);
|
||||
const [dataSource, setDataSource] = useState([]);
|
||||
useEffect(() => {
|
||||
invoke("command_get_pe_data_nt_header").then((resData: any) => {
|
||||
console.log("resData", resData);
|
||||
// 格式化数据
|
||||
let data = cloneDeep(templateData);
|
||||
let base_offset = resData.base_offset;
|
||||
data.signature.offset = base_offset;
|
||||
data.signature.value = "0x" + resData.image_nt_header.signature.toString(16).toUpperCase();
|
||||
console.log("data", data);
|
||||
setDataSource(Object.values(data));
|
||||
});
|
||||
}, []);
|
||||
|
||||
const defaultColumns = [
|
||||
{
|
||||
title: "字段名称",
|
||||
dataIndex: "name",
|
||||
width: "30%",
|
||||
},
|
||||
{
|
||||
title: "偏移量",
|
||||
dataIndex: "offset",
|
||||
defaultSortOrder: "ascend",
|
||||
render: (text) => {
|
||||
return offsetHex ? `0x${text.toString(16).toUpperCase()}` : text;
|
||||
},
|
||||
onHeaderCell: (column) => ({
|
||||
onClick: () => {
|
||||
setOffsetHex(!offsetHex);
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: "字段类型",
|
||||
dataIndex: "field_type",
|
||||
},
|
||||
{
|
||||
title: "字段大小",
|
||||
dataIndex: "size",
|
||||
},
|
||||
{
|
||||
title: "字段值",
|
||||
dataIndex: "value",
|
||||
editable: true,
|
||||
},
|
||||
];
|
||||
|
||||
const replaceNodeByName = (data, name, newNode) => {
|
||||
return data.map((item) => {
|
||||
if (item.name === name) {
|
||||
return newNode;
|
||||
}
|
||||
if (item.children) {
|
||||
return {
|
||||
...item,
|
||||
children: replaceNodeByName(item.children, name, newNode),
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
};
|
||||
|
||||
const handleSave = (row) => {
|
||||
let newData = [...dataSource];
|
||||
newData = replaceNodeByName(newData, row.name, row);
|
||||
setDataSource(newData);
|
||||
};
|
||||
|
||||
const components = {
|
||||
body: {
|
||||
row: EditableRow,
|
||||
cell: EditableCell,
|
||||
},
|
||||
};
|
||||
|
||||
const columns = defaultColumns.map((col) => {
|
||||
if (!col.editable) {
|
||||
return col;
|
||||
}
|
||||
return {
|
||||
...col,
|
||||
onCell: (record) => ({
|
||||
record,
|
||||
editable: col.editable,
|
||||
dataIndex: col.dataIndex,
|
||||
title: col.title,
|
||||
handleSave,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Table
|
||||
components={components}
|
||||
rowClassName={() => "editable-row"}
|
||||
bordered
|
||||
rowKey={(record) => record.name}
|
||||
style={{ width: "100%" }}
|
||||
dataSource={dataSource}
|
||||
columns={columns as any}
|
||||
pagination={false}
|
||||
size="small"
|
||||
sticky={{ offsetHeader: -16 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default function NTHeader() {
|
||||
return (
|
||||
<Flex className={styles.root}>
|
||||
<App />
|
||||
</Flex>
|
||||
);
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
.root {
|
||||
background-color: white;
|
||||
min-height: 500px;
|
||||
width: 100%;
|
||||
margin: 8px;
|
||||
margin-top: 0;
|
||||
|
@ -17,8 +17,8 @@ export default function SiderTree({
|
||||
const [selectedKey, setSelectedKey] = useState<string>(defaultSelectedKey);
|
||||
|
||||
const onSelect: TreeProps["onSelect"] = (selectedKeys, info) => {
|
||||
console.log("selected", selectedKeys, info);
|
||||
let key = info.node.key as string;
|
||||
console.log("onSelect", key);
|
||||
setSelectedKey(key);
|
||||
onTreeSelect(key);
|
||||
};
|
||||
@ -43,8 +43,6 @@ export default function SiderTree({
|
||||
// 设置默认选中的节点
|
||||
setSelectedKey(defaultSelectedKey);
|
||||
}, [treeData]);
|
||||
console.log("selectedKey", selectedKey);
|
||||
|
||||
return (
|
||||
<Flex className={styles.root}>
|
||||
<Tree
|
||||
|
@ -1,13 +1,15 @@
|
||||
.mainLayout {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.sider {
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
flex-shrink: 0;
|
||||
width: 260px;
|
||||
height: calc(100% - 64px);
|
||||
margin: 8px;
|
||||
margin-top: 0;
|
||||
padding: 8px;
|
||||
@ -22,4 +24,8 @@
|
||||
height: 55px;
|
||||
// 圆角
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.content{
|
||||
height: calc(100% - 64px);
|
||||
}
|
@ -7,24 +7,26 @@ const { Content } = Layout;
|
||||
import { SaveOutlined, FolderOpenFilled } from "@ant-design/icons";
|
||||
import SiderTree from "../components/side_tree/SideTree";
|
||||
import DosHeader from "../components/DosHeader/DosHeader";
|
||||
import NtHeader from "../components/NTHeader/NTHeader";
|
||||
import FileHeader from "../components/FileHeader/FileHeader";
|
||||
import { open } from "@tauri-apps/plugin-dialog";
|
||||
|
||||
const SelectNodeMap = {
|
||||
"dos_header": DosHeader,
|
||||
dos_header: <DosHeader />,
|
||||
nt_header: <NtHeader />,
|
||||
file_header: <FileHeader />,
|
||||
};
|
||||
|
||||
export default function MainPage() {
|
||||
const [treeData, setTreeData] = useState([]);
|
||||
const [filePath, setFilePath] = useState("");
|
||||
const [selectedKey, setSelectedKey] = useState("");
|
||||
const [nodeData, setNodeData] = useState([]);
|
||||
|
||||
const openFile = async () => {
|
||||
const file = await open({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
});
|
||||
console.log("file:", file);
|
||||
if (file) {
|
||||
setFilePath(file);
|
||||
}
|
||||
@ -33,26 +35,12 @@ export default function MainPage() {
|
||||
const changeFile = (filePath: string) => {
|
||||
invoke("command_open_file", { filePath }).then(() => {
|
||||
invoke("command_get_file_pe_node_tree_data").then((res) => {
|
||||
console.log("tree nodes:", res);
|
||||
setTreeData(res as any);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const onSelect = (newSelectedKey) => {
|
||||
console.log("newSelectedKey", newSelectedKey);
|
||||
// TODO: 获取节点数据
|
||||
newSelectedKey &&
|
||||
invoke(`command_get_pe_data_${newSelectedKey}`).then((resData: any) => {
|
||||
console.log("resData", resData);
|
||||
// 格式化
|
||||
let ary = [];
|
||||
for (let key in resData) {
|
||||
ary.push(resData[key]);
|
||||
}
|
||||
console.log("ary", ary);
|
||||
setNodeData(ary);
|
||||
});
|
||||
setSelectedKey(newSelectedKey);
|
||||
};
|
||||
|
||||
@ -61,7 +49,6 @@ export default function MainPage() {
|
||||
"tauri://drag-drop",
|
||||
(event) => {
|
||||
const filePath = event.payload.paths[0];
|
||||
console.log("file path:", filePath);
|
||||
setFilePath(filePath);
|
||||
}
|
||||
);
|
||||
@ -76,8 +63,6 @@ export default function MainPage() {
|
||||
}
|
||||
}, [filePath]);
|
||||
|
||||
console.log("selectedKey", selectedKey);
|
||||
|
||||
return (
|
||||
<Layout className={styles.mainLayout}>
|
||||
<Flex className={styles.header}>
|
||||
@ -99,6 +84,7 @@ export default function MainPage() {
|
||||
style={{
|
||||
backgroundColor: "#e5e5e5",
|
||||
paddingBottom: "16px",
|
||||
height: "100%"
|
||||
}}
|
||||
>
|
||||
<Flex className={styles.sider}>
|
||||
@ -108,11 +94,9 @@ export default function MainPage() {
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</Flex>
|
||||
<Content>
|
||||
<Content className={styles.content}>
|
||||
{selectedKey && SelectNodeMap[selectedKey] ? (
|
||||
SelectNodeMap[selectedKey]({
|
||||
defaultData: nodeData,
|
||||
})
|
||||
SelectNodeMap[selectedKey]
|
||||
) : (
|
||||
<Empty description={"请选择一个节点"} />
|
||||
)}
|
||||
|
Loading…
Reference in New Issue
Block a user