From f837e7cdaf4741abc46f6bb19c855b5b53dbee30 Mon Sep 17 00:00:00 2001 From: "381848900@qq.com" Date: Sun, 8 Dec 2024 21:28:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20dos=20header=E7=9A=84=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E5=86=99=E5=AE=8C=E4=BA=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 + pnpm-lock.yaml | 33 ++ src-tauri/Cargo.lock | 543 ++++++++++++++++++++++++- src-tauri/Cargo.toml | 1 + src-tauri/capabilities/default.json | 9 +- src-tauri/src/app_error.rs | 5 + src-tauri/src/commands.rs | 305 +++++++++++++- src-tauri/src/lib.rs | 4 +- src-tauri/src/main.rs | 1 - src-tauri/src/pe_parse/error.rs | 4 +- src-tauri/src/pe_parse/header.rs | 2 + src-tauri/src/pe_parse/mod.rs | 4 +- src-tauri/src/pe_parse/pe.rs | 2 +- src-tauri/src/pe_parse/types.rs | 11 +- src-tauri/src/services/file.rs | 9 +- src-tauri/src/services/mod.rs | 31 +- src/components/DosHeader/DosHeader.tsx | 132 +++--- src/components/side_tree/SideTree.tsx | 63 +-- src/pages/MainPage.tsx | 88 +++- 19 files changed, 1065 insertions(+), 185 deletions(-) diff --git a/package.json b/package.json index ba271b1..cfe8efd 100644 --- a/package.json +++ b/package.json @@ -12,13 +12,16 @@ "dependencies": { "@ant-design/icons": "^5.5.2", "@tauri-apps/api": "^2", + "@tauri-apps/plugin-dialog": "~2", "@tauri-apps/plugin-shell": "^2", "antd": "^5.22.3", + "lodash-es": "^4.17.21", "react": "^19.0.0", "react-dom": "^19.0.0" }, "devDependencies": { "@tauri-apps/cli": "^2", + "@types/lodash-es": "^4.17.12", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^4.2.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 233fc8a..cc16713 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,12 +14,18 @@ importers: '@tauri-apps/api': specifier: ^2 version: 2.1.1 + '@tauri-apps/plugin-dialog': + specifier: ~2 + version: 2.0.1 '@tauri-apps/plugin-shell': specifier: ^2 version: 2.0.1 antd: specifier: ^5.22.3 version: 5.22.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 react: specifier: ^19.0.0 version: 19.0.0 @@ -30,6 +36,9 @@ importers: '@tauri-apps/cli': specifier: ^2 version: 2.1.0 + '@types/lodash-es': + specifier: ^4.17.12 + version: 4.17.12 '@types/react': specifier: ^19.0.0 version: 19.0.1 @@ -644,6 +653,9 @@ packages: engines: {node: '>= 10'} hasBin: true + '@tauri-apps/plugin-dialog@2.0.1': + resolution: {integrity: sha512-fnUrNr6EfvTqdls/ufusU7h6UbNFzLKvHk/zTuOiBq01R3dTODqwctZlzakdbfSp/7pNwTKvgKTAgl/NAP/Z0Q==} + '@tauri-apps/plugin-shell@2.0.1': resolution: {integrity: sha512-akU1b77sw3qHiynrK0s930y8zKmcdrSD60htjH+mFZqv5WaakZA/XxHR3/sF1nNv9Mgmt/Shls37HwnOr00aSw==} @@ -662,6 +674,12 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + + '@types/lodash@4.17.13': + resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} + '@types/react-dom@19.0.1': resolution: {integrity: sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==} @@ -788,6 +806,9 @@ packages: engines: {node: '>=6'} hasBin: true + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -1666,6 +1687,10 @@ snapshots: '@tauri-apps/cli-win32-ia32-msvc': 2.1.0 '@tauri-apps/cli-win32-x64-msvc': 2.1.0 + '@tauri-apps/plugin-dialog@2.0.1': + dependencies: + '@tauri-apps/api': 2.1.1 + '@tauri-apps/plugin-shell@2.0.1': dependencies: '@tauri-apps/api': 2.1.1 @@ -1693,6 +1718,12 @@ snapshots: '@types/estree@1.0.6': {} + '@types/lodash-es@4.17.12': + dependencies: + '@types/lodash': 4.17.13 + + '@types/lodash@4.17.13': {} + '@types/react-dom@19.0.1': dependencies: '@types/react': 19.0.1 @@ -1875,6 +1906,8 @@ snapshots: json5@2.2.3: {} + lodash-es@4.17.21: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index e625a47..0d31a79 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -62,6 +62,61 @@ version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +[[package]] +name = "ashpd" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c39d707614dbcc6bed00015539f488d8e3fe3e66ed60961efc0c90f4b380b3" +dependencies = [ + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.8.5", + "raw-window-handle", + "serde", + "serde_repr", + "tokio", + "url", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "zbus", +] + +[[package]] +name = "async-broadcast" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "atk" version = "0.18.0" @@ -373,6 +428,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -615,6 +679,15 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + [[package]] name = "dlopen2" version = "0.7.0" @@ -638,6 +711,12 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dpi" version = "0.1.1" @@ -703,6 +782,33 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + +[[package]] +name = "enumflags2" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -719,6 +825,43 @@ dependencies = [ "typeid", ] +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" + [[package]] name = "fdeflate" version = "0.3.7" @@ -1080,7 +1223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" dependencies = [ "heck 0.4.1", - "proc-macro-crate 2.0.2", + "proc-macro-crate 2.0.0", "proc-macro-error", "proc-macro2", "quote", @@ -1700,6 +1843,12 @@ dependencies = [ "libc", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "litemap" version = "0.7.4" @@ -1865,6 +2014,19 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + [[package]] name = "nodrop" version = "0.1.14" @@ -1901,7 +2063,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 2.0.2", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.90", @@ -2025,6 +2187,7 @@ checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.6.0", "block2", + "dispatch", "libc", "objc2", ] @@ -2166,6 +2329,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "os_pipe" version = "1.2.1" @@ -2201,6 +2374,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.3" @@ -2396,7 +2575,7 @@ checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", "indexmap 2.7.0", - "quick-xml", + "quick-xml 0.32.0", "serde", "time", ] @@ -2447,14 +2626,22 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" dependencies = [ - "toml_datetime", "toml_edit 0.20.2", ] +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit 0.22.22", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2503,6 +2690,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "quick-xml" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.37" @@ -2685,6 +2881,29 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "rfd" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f6f80a9b882647d9014673ca9925d30ffc9750f2eed2b4490e189eaebd01e8" +dependencies = [ + "ashpd", + "block2", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2700,6 +2919,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "ryu" version = "1.0.18" @@ -2742,6 +2974,12 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -2952,6 +3190,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -3043,6 +3290,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "string_cache" version = "0.8.7" @@ -3327,6 +3580,47 @@ dependencies = [ "walkdir", ] +[[package]] +name = "tauri-plugin-dialog" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0962c2b9210e43cd849790d33bdf3d28c0e50d9884493fb340835244a708b5ba" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.4", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cdaf6701ee5efc83161cf41004aa5aec4d255c9fb2d2b11fe518fe506acc588" +dependencies = [ + "anyhow", + "dunce", + "glob", + "percent-encoding", + "schemars", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.4", + "toml 0.8.2", + "url", + "uuid", +] + [[package]] name = "tauri-plugin-shell" version = "2.0.2" @@ -3440,6 +3734,19 @@ dependencies = [ "toml 0.7.8", ] +[[package]] +name = "tempfile" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "tendril" version = "0.4.3" @@ -3461,6 +3768,7 @@ dependencies = [ "serde_json", "tauri", "tauri-build", + "tauri-plugin-dialog", "tauri-plugin-shell", "thiserror 2.0.4", ] @@ -3563,7 +3871,9 @@ dependencies = [ "libc", "mio", "pin-project-lite", + "signal-hook-registry", "socket2", + "tracing", "windows-sys 0.52.0", ] @@ -3606,9 +3916,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -3623,7 +3933,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -3636,7 +3946,18 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap 2.7.0", + "toml_datetime", + "winnow 0.6.20", ] [[package]] @@ -3652,9 +3973,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "tracing-core" version = "0.1.33" @@ -3703,6 +4036,17 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset", + "tempfile", + "winapi", +] + [[package]] name = "unic-char-property" version = "0.9.0" @@ -3951,6 +4295,66 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wayland-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" +dependencies = [ + "bitflags 2.6.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +dependencies = [ + "proc-macro2", + "quick-xml 0.36.2", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.76" @@ -4402,6 +4806,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.52.0" @@ -4488,6 +4901,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "xdg-home" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "yoke" version = "0.7.5" @@ -4512,6 +4935,63 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zbus" +version = "5.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1162094dc63b1629fcc44150bcceeaa80798cd28bcbe7fa987b65a034c258608" +dependencies = [ + "async-broadcast", + "async-recursion", + "async-trait", + "enumflags2", + "event-listener", + "futures-core", + "futures-util", + "hex", + "nix", + "ordered-stream", + "serde", + "serde_repr", + "static_assertions", + "tokio", + "tracing", + "uds_windows", + "windows-sys 0.59.0", + "winnow 0.6.20", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cd2dcdce3e2727f7d74b7e33b5a89539b3cc31049562137faf7ae4eb86cd16d" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.90", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "856b7a38811f71846fd47856ceee8bccaec8399ff53fb370247e66081ace647b" +dependencies = [ + "serde", + "static_assertions", + "winnow 0.6.20", + "zvariant", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -4575,3 +5055,46 @@ dependencies = [ "quote", "syn 2.0.90", ] + +[[package]] +name = "zvariant" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1200ee6ac32f1e5a312e455a949a4794855515d34f9909f4a3e082d14e1a56f" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "url", + "winnow 0.6.20", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687e3b97fae6c9104fbbd36c73d27d149abf04fb874e2efbd84838763daa8916" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.90", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20d1d011a38f12360e5fcccceeff5e2c42a8eb7f27f0dcba97a0862ede05c9c6" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "static_assertions", + "syn 2.0.90", + "winnow 0.6.20", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 8cd952c..488baee 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -25,4 +25,5 @@ serde_json = "1" thiserror = "2.0.4" bitflags = "2.6.0" memmap = "0.7.0" +tauri-plugin-dialog = "2" diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 3bb4cc4..ba20fb1 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -2,9 +2,12 @@ "$schema": "../gen/schemas/desktop-schema.json", "identifier": "default", "description": "Capability for the main window", - "windows": ["main"], + "windows": [ + "main" + ], "permissions": [ "core:default", - "shell:allow-open" + "shell:allow-open", + "dialog:default" ] -} +} \ No newline at end of file diff --git a/src-tauri/src/app_error.rs b/src-tauri/src/app_error.rs index 5b685ad..9519dfe 100644 --- a/src-tauri/src/app_error.rs +++ b/src-tauri/src/app_error.rs @@ -1,5 +1,7 @@ use thiserror; +use crate::pe_parse::error::{self, PEParseError}; + #[derive(Debug, thiserror::Error)] pub enum AppError { #[error(transparent)] @@ -8,6 +10,9 @@ pub enum AppError { // 未打开文件映射 #[error("文件未打开!")] NoFileOpened, + + #[error(transparent)] + PeParseError(#[from] PEParseError), } impl serde::Serialize for AppError { diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index fe2f619..0efb3fd 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -1,9 +1,21 @@ -use crate::{app_error::AppError, services}; -use serde::Serialize; +use crate::{ + app_error::AppError, + pe_parse::{header::ImageDosHeader, pe::PE}, + services::{self, GLOBAL_FILE_DATA}, +}; +use serde::{ser::SerializeStruct, Serialize, Serializer}; +use serde_json::Value; #[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, @@ -14,8 +26,8 @@ pub struct PeNodeTreeData { // TODO: 获取PE节点树的JSON数据 #[tauri::command] pub fn command_get_file_pe_node_tree_data() -> Result, AppError> { - // 1. 如果全局内存映射句柄为空,则返回错误 - if unsafe { services::GLOBAL_MEMMAP_HANDLE.is_none() } { + // 1. 如果没有打开文件,则返回错误 + if GLOBAL_FILE_DATA.lock().unwrap().is_none() { return Err(AppError::NoFileOpened); } // 从文件路径中获取文件名 @@ -26,28 +38,28 @@ pub fn command_get_file_pe_node_tree_data() -> Result, AppEr }; let result = PeNodeTreeData { title: format!("文件: {}", file_name), - key: "fileName".to_string(), + key: "file_name".to_string(), children: vec![ PeNodeTreeData { title: "DOS 头部".to_string(), - key: "DOS Header".to_string(), + key: "dos_header".to_string(), children: vec![], // 空数组表示没有子节点 }, PeNodeTreeData { title: "NT 头部".to_string(), - key: "NT Headers".to_string(), + key: "nt_header".to_string(), children: vec![ PeNodeTreeData { title: "文件头部".to_string(), - key: "File Header".to_string(), + key: "file_header".to_string(), children: vec![], }, PeNodeTreeData { title: "可选头部".to_string(), - key: "Optional Header".to_string(), + key: "optional_header".to_string(), children: vec![PeNodeTreeData { title: "数据目录".to_string(), - key: "Data Directories".to_string(), + key: "data_directories".to_string(), children: vec![], }], }, @@ -55,7 +67,7 @@ pub fn command_get_file_pe_node_tree_data() -> Result, AppEr }, PeNodeTreeData { title: "节区头部".to_string(), - key: "Section Headers".to_string(), + key: "section_header".to_string(), children: vec![], }, ], @@ -66,9 +78,276 @@ pub fn command_get_file_pe_node_tree_data() -> Result, AppEr // 命令,打开文件 #[tauri::command] pub fn command_open_file(file_path: &str) -> Result<(), AppError> { + let mmap = Some(services::file::mmap_mut_file(file_path)?); + // 将内存clone到Vec中 + let mmap = mmap.as_ref().unwrap(); + let mmap = mmap.to_vec(); + *services::GLOBAL_FILE_DATA.lock().unwrap() = Some(services::PeData(mmap)); unsafe { - services::GLOBAL_MEMMAP_HANDLE = Some(services::file::mmap_mut_file(file_path)?); services::GLOBAL_FILE_PATH = Some(file_path.to_string()); - Ok(()) + } + Ok(()) +} + +#[derive(Serialize, Default)] +pub struct ResponseDOSHeaderData { + name: String, + offset: usize, + size: usize, + field_type: String, + value: Option, + children: Option>, +} + +fn serialize_field( + state: &mut S, + name: &'static str, + value: Option, + size: usize, + field_type: &str, + offset: usize, + children: Option>, +) -> Result<(), S::Error> +where + S: serde::ser::SerializeStruct, +{ + state.serialize_field( + name, + &ResponseDOSHeaderData { + name: name.to_string(), + value, + size, + field_type: field_type.to_string(), + offset, + children, + }, + ) +} + + +impl Serialize for ImageDosHeader { + fn serialize( + &self, + serializer: S, + ) -> Result<::Ok, ::Error> + where + S: serde::Serializer, + { + let mut state = serializer.serialize_struct("ResponseDOSHeaderData", 19)?; + // 序列化每个字段 + serialize_field( + &mut state, + "e_magic", + Some(format!("0x{:04X}", self.e_magic)), + std::mem::size_of_val(&self.e_magic), + "u16", + offset_of!(self, e_magic), + None, + )?; + serialize_field( + &mut state, + "e_cblp", + Some(format!("0x{:04X}", self.e_cblp)), + std::mem::size_of_val(&self.e_cblp), + "u16", + offset_of!(self, e_cblp), + None, + )?; + serialize_field( + &mut state, + "e_cp", + Some(format!("0x{:04X}", self.e_cp)), + std::mem::size_of_val(&self.e_cp), + "u16", + offset_of!(self, e_cp), + None, + )?; + serialize_field( + &mut state, + "e_crlc", + Some(format!("0x{:04X}", self.e_crlc)), + std::mem::size_of_val(&self.e_crlc), + "u16", + offset_of!(self, e_crlc), + None, + )?; + serialize_field( + &mut state, + "e_cparhdr", + Some(format!("0x{:04X}", self.e_cparhdr)), + std::mem::size_of_val(&self.e_cparhdr), + "u16", + offset_of!(self, e_cparhdr), + None, + )?; + serialize_field( + &mut state, + "e_minalloc", + Some(format!("0x{:04X}", self.e_minalloc)), + std::mem::size_of_val(&self.e_minalloc), + "u16", + offset_of!(self, e_minalloc), + None, + )?; + serialize_field( + &mut state, + "e_maxalloc", + Some(format!("0x{:04X}", self.e_maxalloc)), + std::mem::size_of_val(&self.e_maxalloc), + "u16", + offset_of!(self, e_maxalloc), + None, + )?; + serialize_field( + &mut state, + "e_ss", + Some(format!("0x{:04X}", self.e_ss)), + std::mem::size_of_val(&self.e_ss), + "u16", + offset_of!(self, e_ss), + None, + )?; + serialize_field( + &mut state, + "e_sp", + Some(format!("0x{:04X}", self.e_sp)), + std::mem::size_of_val(&self.e_sp), + "u16", + offset_of!(self, e_sp), + None, + )?; + serialize_field( + &mut state, + "e_csum", + Some(format!("0x{:04X}", self.e_csum)), + std::mem::size_of_val(&self.e_csum), + "u16", + offset_of!(self, e_csum), + None, + )?; + serialize_field( + &mut state, + "e_ip", + Some(format!("0x{:04X}", self.e_ip)), + std::mem::size_of_val(&self.e_ip), + "u16", + offset_of!(self, e_ip), + None, + )?; + serialize_field( + &mut state, + "e_cs", + Some(format!("0x{:04X}", self.e_cs)), + std::mem::size_of_val(&self.e_cs), + "u16", + offset_of!(self, e_cs), + None, + )?; + serialize_field( + &mut state, + "e_lfarlc", + Some(format!("0x{:04X}", self.e_lfarlc)), + std::mem::size_of_val(&self.e_lfarlc), + "u16", + offset_of!(self, e_lfarlc), + None, + )?; + serialize_field( + &mut state, + "e_ovno", + Some(format!("0x{:04X}", self.e_ovno)), + std::mem::size_of_val(&self.e_ovno), + "u16", + offset_of!(self, e_ovno), + None, + )?; + + // e_res 序列化,带 children + let mut e_res_children = Vec::new(); + for (index, value) in self.e_res.iter().enumerate() { + e_res_children.push(ResponseDOSHeaderData { + name: format!("e_res[{}]", index), + value: Some(format!("0x{:04X}", value)), + size: std::mem::size_of_val(value), + field_type: "u16".to_string(), + offset: offset_of!(self, e_res) + index * std::mem::size_of::(), + children: None, + }); + } + serialize_field( + &mut state, + "e_res", + None, + std::mem::size_of_val(&self.e_res), + "[u16;4]", + offset_of!(self, e_res), + Some(e_res_children), + )?; + // e_oemid 序列化 + serialize_field( + &mut state, + "e_oemid", + Some(format!("0x{:04X}", self.e_oemid)), + std::mem::size_of_val(&self.e_oemid), + "u16", + offset_of!(self, e_oemid), + None, + )?; + + // e_oeminfo 序列化 + serialize_field( + &mut state, + "e_oeminfo", + Some(format!("0x{:04X}", self.e_oeminfo)), + std::mem::size_of_val(&self.e_oeminfo), + "u16", + offset_of!(self, e_oeminfo), + None, + )?; + + + + // e_res2 序列化 + let mut e_res2_children = Vec::new(); + for (index, value) in self.e_res2.iter().enumerate() { + e_res2_children.push(ResponseDOSHeaderData { + name: format!("e_res2[{}]", index), + value: Some(format!("0x{:04X}", value)), + size: std::mem::size_of_val(value), + field_type: "u16".to_string(), + offset: offset_of!(self, e_res2) + index * std::mem::size_of::(), + children: None, + }); + } + serialize_field( + &mut state, + "e_res2", + None, + std::mem::size_of_val(&self.e_res2), + "[u16;10]", + offset_of!(self, e_res2), + Some(e_res2_children), + )?; + + // e_lfanew 序列化 + serialize_field( + &mut state, + "e_lfanew", + Some(format!("0x{:04X}", self.e_lfanew.0)), // 假设 Offset 是简单的 tuple struct + std::mem::size_of_val(&self.e_lfanew), + "Offset", + offset_of!(self, e_lfanew), + None, + )?; + state.end() } } + +// 命令,获取DOS头数据 +#[tauri::command] +pub fn command_get_pe_data_dos_header() -> Result { + 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()) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 515ac62..75497e6 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -7,10 +7,12 @@ pub mod services; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() + .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_shell::init()) .invoke_handler(tauri::generate_handler![ commands::command_open_file, - commands::command_get_file_pe_node_tree_data + commands::command_get_file_pe_node_tree_data, + commands::command_get_pe_data_dos_header, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 5075516..0eb8aae 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,7 +1,6 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - fn main() { test_tauri_lib::run() } diff --git a/src-tauri/src/pe_parse/error.rs b/src-tauri/src/pe_parse/error.rs index 503316b..5dfe263 100644 --- a/src-tauri/src/pe_parse/error.rs +++ b/src-tauri/src/pe_parse/error.rs @@ -11,5 +11,5 @@ pub enum PEParseError { #[error("Invalid optional header size")] InvalidOptionalSize, #[error("解析超出了文件范围")] - OutOfBounds -} \ No newline at end of file + OutOfBounds, +} diff --git a/src-tauri/src/pe_parse/header.rs b/src-tauri/src/pe_parse/header.rs index 0c4c9f1..efa3fc4 100644 --- a/src-tauri/src/pe_parse/header.rs +++ b/src-tauri/src/pe_parse/header.rs @@ -1,6 +1,8 @@ use super::types::*; use bitflags::bitflags; +use serde::Serialize; #[repr(C)] +#[derive(Debug, Clone, Copy)] pub struct ImageDosHeader { pub e_magic: u16, // Magic number 固定值 0x5A4D pub e_cblp: u16, diff --git a/src-tauri/src/pe_parse/mod.rs b/src-tauri/src/pe_parse/mod.rs index 54df619..404d0fd 100644 --- a/src-tauri/src/pe_parse/mod.rs +++ b/src-tauri/src/pe_parse/mod.rs @@ -1,4 +1,4 @@ +pub mod error; pub mod header; -pub mod types; pub mod pe; -pub mod error; \ No newline at end of file +pub mod types; diff --git a/src-tauri/src/pe_parse/pe.rs b/src-tauri/src/pe_parse/pe.rs index ac82222..52b8b52 100644 --- a/src-tauri/src/pe_parse/pe.rs +++ b/src-tauri/src/pe_parse/pe.rs @@ -1,5 +1,5 @@ -use std::ops::{Deref, DerefMut}; use super::{error::PEParseError, header::*}; +use std::ops::{Deref, DerefMut}; pub trait PE: Deref + DerefMut + Sized { /// Get a reference to a type at a given offset. diff --git a/src-tauri/src/pe_parse/types.rs b/src-tauri/src/pe_parse/types.rs index 385bff0..ff5d4f1 100644 --- a/src-tauri/src/pe_parse/types.rs +++ b/src-tauri/src/pe_parse/types.rs @@ -1,4 +1,9 @@ -#[repr(C)] -pub struct Offset(pub u32); +use serde::Serialize; -pub struct RVA(pub u32); \ No newline at end of file + +#[repr(C)] +#[derive(Debug, Clone, Copy, Serialize)] +pub struct Offset(pub u32); +#[repr(C)] +#[derive(Debug, Clone, Copy, Serialize)] +pub struct RVA(pub u32); diff --git a/src-tauri/src/services/file.rs b/src-tauri/src/services/file.rs index 5ed04b0..83e5100 100644 --- a/src-tauri/src/services/file.rs +++ b/src-tauri/src/services/file.rs @@ -1,15 +1,12 @@ use memmap::*; // TODO: 打开文件,并将文件映射到内存 -pub fn mmap_mut_file(file_path: &str) -> Result { - let file = std::fs::OpenOptions::new() - .read(true) - .write(true) - .open(file_path)?; +pub fn mmap_mut_file(file_path: &str) -> Result { + let file = std::fs::OpenOptions::new().read(true).open(file_path)?; unsafe { MmapOptions::new() - .map_mut(&file) + .map(&file) .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) } } diff --git a/src-tauri/src/services/mod.rs b/src-tauri/src/services/mod.rs index fe427b6..1b3a966 100644 --- a/src-tauri/src/services/mod.rs +++ b/src-tauri/src/services/mod.rs @@ -1,9 +1,30 @@ -use memmap::MmapMut; +use memmap::{Mmap, MmapMut}; +use std::{ + ops::{Deref, DerefMut}, + sync::Mutex, +}; +use crate::pe_parse::pe::PE; pub mod file; -// 映射到内存的文件句柄 -pub static mut GLOBAL_MEMMAP_HANDLE: Option = None; - // 全局文件路径 -pub static mut GLOBAL_FILE_PATH: Option = None; \ No newline at end of file +pub static mut GLOBAL_FILE_PATH: Option = None; + +pub(crate) struct PeData(pub Vec); +// 实现Deref +impl Deref for PeData { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +// 实现DerefMut +impl DerefMut for PeData { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl PE for PeData {} +// 文件的内存映射clone +pub static GLOBAL_FILE_DATA: Mutex> = Mutex::new(None); diff --git a/src/components/DosHeader/DosHeader.tsx b/src/components/DosHeader/DosHeader.tsx index 0e21752..34e9d33 100644 --- a/src/components/DosHeader/DosHeader.tsx +++ b/src/components/DosHeader/DosHeader.tsx @@ -2,17 +2,18 @@ import styles from "./DosHeader.module.scss"; import { Flex } from "antd"; import React, { useContext, useEffect, useRef, useState } from "react"; import type { GetRef, InputRef, TableProps } from "antd"; -import { Button, Form, Input, Popconfirm, Table } from "antd"; +import { Form, Input, Table } from "antd"; type FormInstance = GetRef>; const EditableContext = React.createContext | null>(null); interface Item { - key: string; - name: string; - age: string; - address: string; + name: string; // 字段名称 + offset: string; // 偏移 + size: Number; // 字段大小 + value: string; // 字段值 + children?: Item[]; } interface EditableRowProps { @@ -65,7 +66,6 @@ const EditableCell: React.FC> = ({ const save = async () => { try { const values = await form.validateFields(); - toggleEdit(); handleSave({ ...record, ...values }); } catch (errInfo) { @@ -82,7 +82,7 @@ const EditableCell: React.FC> = ({ name={dataIndex} rules={[{ required: true, message: `${title} is required.` }]} > - + ) : (
> = ({ }; interface DataType { - key: React.Key; - name: string; - age: string; - address: string; + name: string; // 字段名称 + offset: string; // 偏移 + size: string | Number; // 字段大小 + value: string; // 字段值 + field_type: string; // 字段类型 + children?: DataType[]; } type ColumnTypes = Exclude["columns"], undefined>; -const App: React.FC = () => { - const [dataSource, setDataSource] = useState([ - { - key: "0", - name: "Edward King 0", - age: "32", - address: "London, Park Lane no. 0", - }, - { - key: "1", - name: "Edward King 1", - age: "32", - address: "London, Park Lane no. 1", - }, - ]); - - const [count, setCount] = useState(2); - - const handleDelete = (key: React.Key) => { - const newData = dataSource.filter((item) => item.key !== key); - setDataSource(newData); - }; +const App = ({ defaultData = [] }) => { + const [dataSource, setDataSource] = useState(defaultData); + useEffect(()=>{ + setDataSource(defaultData) + }, [defaultData]) const defaultColumns: (ColumnTypes[number] & { editable?: boolean; dataIndex: string; })[] = [ { - title: "name", + title: "字段名称", dataIndex: "name", width: "30%", + }, + { + title: "偏移量", + dataIndex: "offset", + }, + { + title: "字段类型", + dataIndex: "field_type", + }, + { + title: "字段大小", + dataIndex: "size", + }, + { + title: "字段值", + dataIndex: "value", editable: true, }, - { - title: "age", - dataIndex: "age", - }, - { - title: "address", - dataIndex: "address", - }, - { - title: "operation", - dataIndex: "operation", - render: (_, record) => - dataSource.length >= 1 ? ( - handleDelete(record.key)} - > - Delete - - ) : null, - }, ]; - const handleAdd = () => { - const newData: DataType = { - key: count, - name: `Edward King ${count}`, - age: "32", - address: `London, Park Lane no. ${count}`, - }; - setDataSource([...dataSource, newData]); - setCount(count + 1); + const replaceNodeByName = ( + data: DataType[], + name: string, + newNode: DataType + ): DataType[] => { + 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: DataType) => { - const newData = [...dataSource]; - const index = newData.findIndex((item) => row.key === item.key); - const item = newData[index]; - newData.splice(index, 1, { - ...item, - ...row, - }); + let newData = [...dataSource]; + newData = replaceNodeByName(newData, row.name, row); setDataSource(newData); }; @@ -213,18 +196,21 @@ const App: React.FC = () => { components={components} rowClassName={() => "editable-row"} bordered + rowKey={(record) => record.name} style={{ width: "100%" }} dataSource={dataSource} columns={columns as ColumnTypes} pagination={false} + size="small" /> ); }; -export default function DosHeader() { +export default function DosHeader({ defaultData }) { + console.log("DosHeader defaultData:", defaultData); return ( - + ); } diff --git a/src/components/side_tree/SideTree.tsx b/src/components/side_tree/SideTree.tsx index aa278b7..0adb9d4 100644 --- a/src/components/side_tree/SideTree.tsx +++ b/src/components/side_tree/SideTree.tsx @@ -5,60 +5,11 @@ import { DownOutlined } from "@ant-design/icons"; import type { TreeProps } from "antd"; import { useEffect, useState } from "react"; -// const treeData: TreeDataNode[] = [ -// { -// title: "文件: Test.exe", -// key: "0-0", -// children: [ -// { -// title: "Dos 头部", -// key: "0-0-0", -// }, -// { -// title: "Nt 头部", -// key: "0-0-1", -// children: [ -// { -// title: "文件头部", -// key: "0-0-1-0", -// }, -// { -// title: "可选头部", -// key: "0-0-2-0", -// children: [ -// { -// title: "数据目录", -// key: "0-0-1-1", -// }, -// ], -// }, -// ], -// }, -// { -// title: "节 头部", -// key: "0-0-2", -// }, -// { -// title: "导入目录", -// key: "0-0-3", -// }, -// { -// title: "资源目录", -// key: "0-0-4", -// }, -// { -// title: "地址转换", -// key: "0-0-5", -// }, -// { -// title: "依赖性分析", -// key: "0-0-6", -// }, -// ], -// }, -// ]; - -export default function SiderTree({ treeData, defaultSelectedKey }) { +export default function SiderTree({ + treeData, + defaultSelectedKey, + onSelect: onTreeSelect, +}) { // 展开的节点 const [expandedKeys, setExpandedKeys] = useState([]); @@ -67,7 +18,9 @@ export default function SiderTree({ treeData, defaultSelectedKey }) { const onSelect: TreeProps["onSelect"] = (selectedKeys, info) => { console.log("selected", selectedKeys, info); - setSelectedKey(selectedKeys[0] as any); + let key = info.node.key as string; + setSelectedKey(key); + onTreeSelect(key); }; const onExpand: TreeProps["onExpand"] = (_expandedKeys) => { diff --git a/src/pages/MainPage.tsx b/src/pages/MainPage.tsx index f5b5d32..50f98c1 100644 --- a/src/pages/MainPage.tsx +++ b/src/pages/MainPage.tsx @@ -1,16 +1,60 @@ import styles from "./MainPage.module.scss"; import { useEffect, useState } from "react"; -import { Layout, Flex, Button } from "antd"; +import { Layout, Flex, Button, Empty } from "antd"; import { listen } from "@tauri-apps/api/event"; import { invoke } from "@tauri-apps/api/core"; const { Content } = Layout; -import { SaveOutlined } from "@ant-design/icons"; +import { SaveOutlined, FolderOpenFilled } from "@ant-design/icons"; import SiderTree from "../components/side_tree/SideTree"; import DosHeader from "../components/DosHeader/DosHeader"; +import { open } from "@tauri-apps/plugin-dialog"; + +const SelectNodeMap = { + "dos_header": DosHeader, +}; 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); + } + }; + + 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); + }; useEffect(() => { const unlisten = listen<{ paths: Array }>( @@ -19,12 +63,6 @@ export default function MainPage() { const filePath = event.payload.paths[0]; console.log("file path:", filePath); setFilePath(filePath); - 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); - }); - }); } ); return () => { @@ -32,22 +70,52 @@ export default function MainPage() { }; }, []); + useEffect(() => { + if (filePath) { + changeFile(filePath); + } + }, [filePath]); + + console.log("selectedKey", selectedKey); + return ( + - + - + {selectedKey && SelectNodeMap[selectedKey] ? ( + SelectNodeMap[selectedKey]({ + defaultData: nodeData, + }) + ) : ( + + )}