Compare commits
548 commits
0.21.5
...
new_engine
Author | SHA1 | Date | |
---|---|---|---|
|
a072527138 | ||
|
a19aeadb54 | ||
|
775227942a | ||
|
6f6debb212 | ||
|
f64ba09a9c | ||
|
2b23bbd82c | ||
|
9cc9518f8b | ||
|
73d07cddc3 | ||
|
c8b7151b9e | ||
|
892111a8b1 | ||
|
7cea8ee512 | ||
|
c38ed925b0 | ||
|
22bb757726 | ||
|
d61d759db2 | ||
|
7ef371957a | ||
|
97a85f9ddc | ||
|
a077743de8 | ||
|
07742a5069 | ||
|
a12be6bfc7 | ||
|
9719b0cf03 | ||
|
fbf6afdfc8 | ||
|
3cb5dc0165 | ||
|
fd0faea9ea | ||
|
01e2e0877b | ||
|
4e2a8f6bd7 | ||
|
58366f48fe | ||
|
b98edf6944 | ||
|
f989fdfea1 | ||
|
4e600eb986 | ||
|
2d6eaa917f | ||
|
ca7d4caa7a | ||
|
34904bdc5d | ||
|
489b85fd98 | ||
|
2661b8fe4b | ||
|
d91115ff78 | ||
|
0fae05c2cb | ||
|
5e6a1c7119 | ||
|
8d7e01c027 | ||
|
b1ad055eef | ||
|
7dd9014a38 | ||
|
4e3fa5899c | ||
|
369f10188c | ||
|
ff42cecb07 | ||
|
c94f78a530 | ||
|
b5756f9ccb | ||
|
65fb4a86b6 | ||
|
e66bc7d8dc | ||
|
dcf21fa50a | ||
|
0af36bdcd9 | ||
|
fd76e896cc | ||
|
427d8ecdcb | ||
|
a824260064 | ||
|
a777f1fa5f | ||
|
5f2337741a | ||
|
932120cb36 | ||
|
a8c008cf74 | ||
|
6b853f8caf | ||
|
66565a557a | ||
|
371448d0ec | ||
|
b0cd7fe38f | ||
|
4b868bb208 | ||
|
214b356f84 | ||
|
0030ea9481 | ||
|
3441255566 | ||
|
941ee6cfd1 | ||
|
c5508535c1 | ||
|
bf93a5eacc | ||
|
d03a8f254a | ||
|
0a88da1410 | ||
|
6f9a4c0d46 | ||
|
e0b1e0205f | ||
|
161c697104 | ||
|
573452ec09 | ||
|
166c797a20 | ||
|
0e11189644 | ||
|
daf585151c | ||
|
1cba371cc2 | ||
|
4992474e83 | ||
|
29915ca620 | ||
|
4a41c33596 | ||
|
b2a8952c71 | ||
|
036be8d3bc | ||
|
a5675bda90 | ||
|
a7cf9cc3e3 | ||
|
2b8b00d5b0 | ||
|
8e710e637a | ||
|
53f5c5cd71 | ||
|
eaef5c819e | ||
|
b6cdc9f484 | ||
|
031bd4f734 | ||
|
91fb7cdc83 | ||
|
a040c72217 | ||
|
1a1a20895b | ||
|
ddf40c9260 | ||
|
d7c834042f | ||
|
1958ed7fa9 | ||
|
40fed25637 | ||
|
dce666c262 | ||
|
29b339436c | ||
|
d8bdac174d | ||
|
fb5a81ebda | ||
|
4e17fb4f58 | ||
|
cba31d826a | ||
|
cbf26d125d | ||
|
84ea44829a | ||
|
ce92b98527 | ||
|
88fa2d2a47 | ||
|
f1b0cae1a5 | ||
|
12b52902e4 | ||
|
d9e1fe5859 | ||
|
2b876e2cc3 | ||
|
7a25a52427 | ||
|
37372cdab4 | ||
|
ea38ab3696 | ||
|
9c6786a27b | ||
|
6875968d97 | ||
|
aa3e790fb1 | ||
|
6aeb713488 | ||
|
b8567d32cc | ||
|
75bf036137 | ||
|
255742f371 | ||
|
62d96a16df | ||
|
6c695c12a7 | ||
|
7eb565d788 | ||
|
2d1ebcc11b | ||
|
6f9dc0ab88 | ||
|
cb6ef45d0c | ||
|
c4ed9c310d | ||
|
633561adbf | ||
|
3cf8d86c34 | ||
|
38854e945a | ||
|
209fbb6282 | ||
|
69edce7d77 | ||
|
24d61c4375 | ||
|
1c73007e4a | ||
|
a5a0f55149 | ||
|
4053a8fe72 | ||
|
11e00f7113 | ||
|
6232836fb6 | ||
|
745f4b69f2 | ||
|
944133caa7 | ||
|
ef7ceefa41 | ||
|
d48955d45a | ||
|
0c92f935e4 | ||
|
a7aa3fa440 | ||
|
180f061bcc | ||
|
33c25e8255 | ||
|
7a161f577a | ||
|
f02f828571 | ||
|
c9939e23ec | ||
|
20d0155130 | ||
|
43997ab169 | ||
|
b649b98cb5 | ||
|
2467b48802 | ||
|
03d71d6f9f | ||
|
66e9f95dc3 | ||
|
e6b567532d | ||
|
3e55a655da | ||
|
507f884635 | ||
|
fa5d744aac | ||
|
5437efc2c5 | ||
|
1adff58591 | ||
|
eab62138aa | ||
|
19ab6076c4 | ||
|
1b143c89e6 | ||
|
7337f15ec9 | ||
|
15026849d2 | ||
|
862cdb1931 | ||
|
6e7b46d791 | ||
|
47c8938c7e | ||
|
5f134f783a | ||
|
1d560bd0be | ||
|
71a7336730 | ||
|
497fb2a86f | ||
|
c9e16cb180 | ||
|
50396d7291 | ||
|
0429225c56 | ||
|
cd22c3db2b | ||
|
c3cedba150 | ||
|
89a302e5d9 | ||
|
7e5e02b4b4 | ||
|
acc913769b | ||
|
ad8a841f43 | ||
|
d0129d4c63 | ||
|
662e0bf9b1 | ||
|
ee6b536009 | ||
|
799f186852 | ||
|
7d4e535c34 | ||
|
6247fa5bbc | ||
|
9bb0549ad2 | ||
|
e38e246bf5 | ||
|
6ca7d99f66 | ||
|
739de0fec8 | ||
|
152fcc44a5 | ||
|
d1032d59fd | ||
|
26a2f46197 | ||
|
a9d1016a52 | ||
|
4358f31242 | ||
|
574754fce6 | ||
|
6e5cc3bccc | ||
|
011647aa30 | ||
|
a4a455d0ff | ||
|
06653d024b | ||
|
f514c60cba | ||
|
109d30b5e6 | ||
|
ce2291a23c | ||
|
b457ed99cd | ||
|
c4ca232b3a | ||
|
a9c6f347a2 | ||
|
22d1db8c7f | ||
|
75a1374c0c | ||
|
934ce1f3f8 | ||
|
8600bc3ab3 | ||
|
55d4b4fc66 | ||
|
2be53035b6 | ||
|
d6bf25df67 | ||
|
787e02181a | ||
|
3977fcaed9 | ||
|
9cd97e78e6 | ||
|
1675498d4d | ||
|
d93f1ae749 | ||
|
e9261a9900 | ||
|
f58a97a657 | ||
|
eef00f73a4 | ||
|
7695927eec | ||
|
e5b594c347 | ||
|
67c568daf8 | ||
|
4006954bc1 | ||
|
10e2e60183 | ||
|
eb3185224b | ||
|
83548d4c8a | ||
|
2246026434 | ||
|
ff864f9b8f | ||
|
f626316b1e | ||
|
7951bc1bcf | ||
|
19ec41b7e2 | ||
|
3aafbdd269 | ||
|
4c74232688 | ||
|
74910c4658 | ||
|
eabd6a8604 | ||
|
820e3ea65d | ||
|
d7f360e337 | ||
|
e36cc77c06 | ||
|
e85fb741ee | ||
|
12f40cf289 | ||
|
cc274319bf | ||
|
d46489fabb | ||
|
7c534cca2a | ||
|
d9af12b567 | ||
|
fae9d6681d | ||
|
1f488862c6 | ||
|
963671a73e | ||
|
2a083d8739 | ||
|
44bb6e8261 | ||
|
f9c35f77a6 | ||
|
e14547c497 | ||
|
44c5b4bc49 | ||
|
0fb88ab760 | ||
|
a754fb5153 | ||
|
34c8ad8dcc | ||
|
d1e47539fc | ||
|
2335e69dce | ||
|
5066a44132 | ||
|
6bb862d626 | ||
|
e6f3f4380f | ||
|
05f770c8a4 | ||
|
fd1e8c4856 | ||
|
8f862d4fdb | ||
|
3945c9b89f | ||
|
5645599c58 | ||
|
115d338a70 | ||
|
5967865028 | ||
|
78714f6755 | ||
|
10295bd0dd | ||
|
24cf452024 | ||
|
55b7a759ff | ||
|
92d0a8f754 | ||
|
d69aca6554 | ||
|
7bce6fac92 | ||
|
812af96d82 | ||
|
0edd935d28 | ||
|
446dba9d64 | ||
|
0504af6fdc | ||
|
bfbf18404d | ||
|
750b589575 | ||
|
9351f697ff | ||
|
ae133acc59 | ||
|
753b8ee893 | ||
|
b96772190a | ||
|
a2d7169a82 | ||
|
57e4d6dfa0 | ||
|
cd110eafa6 | ||
|
fc2d8f07b1 | ||
|
30d05a9fed | ||
|
65670a704c | ||
|
8e189f88df | ||
|
0f31b1401e | ||
|
07dbfa3f96 | ||
|
ac1f24ec77 | ||
|
a3425115b8 | ||
|
0f2ede398d | ||
|
6fdc69415b | ||
|
1dccf3f15a | ||
|
4d948475d8 | ||
|
bf3adbe4c6 | ||
|
516949a6e6 | ||
|
2ef8d770e4 | ||
|
1b2ea8c276 | ||
|
f2e343d8bf | ||
|
967375243c | ||
|
8bddbe7d1f | ||
|
3507698136 | ||
|
64e1aa18b8 | ||
|
95c838181f | ||
|
90ff19692d | ||
|
d95e533441 | ||
|
fa954394cc | ||
|
1e1d5c6e17 | ||
|
47637ef152 | ||
|
a01d2c6003 | ||
|
2e7aa8133a | ||
|
f386eda430 | ||
|
be65f8ae06 | ||
|
5edd5c10ee | ||
|
2cbd78fb9e | ||
|
e7455409ff | ||
|
f34894b9fd | ||
|
5c98152c58 | ||
|
f863caac9d | ||
|
1ac6e6a4f0 | ||
|
40b77a713f | ||
|
d16c438069 | ||
|
afce02430a | ||
|
be2cdc7dfe | ||
|
f074dfc5ca | ||
|
d9325c22fe | ||
|
e1c0b08fc0 | ||
|
7ab6dd4285 | ||
|
2201a9b10c | ||
|
76ff756598 | ||
|
3e1afd1e00 | ||
|
8932aebc02 | ||
|
5b26775463 | ||
|
f2cdf7dc3b | ||
|
4dcd6b26a3 | ||
|
aa0ab13411 | ||
|
6e481fbb4d | ||
|
14e72cb03a | ||
|
bc3193420c | ||
|
021da9df4c | ||
|
126b36a672 | ||
|
49e8e02b77 | ||
|
7e1e1ab61e | ||
|
337da5e632 | ||
|
0a634ebcbd | ||
|
b064495db8 | ||
|
8f6c8ef5cc | ||
|
6982aace9b | ||
|
f666fe63db | ||
|
ee6ce579e3 | ||
|
4d50d581fa | ||
|
7d16c1d48d | ||
|
c9db871c12 | ||
|
0a2f115056 | ||
|
616464ba29 | ||
|
aee2831b25 | ||
|
c70d448056 | ||
|
d23c1a682a | ||
|
dccc335886 | ||
|
b60a49bef3 | ||
|
53a0887112 | ||
|
a5b2f00f9b | ||
|
4f6efe5195 | ||
|
4f9f31ef71 | ||
|
daea6d8b16 | ||
|
6f104ec94c | ||
|
fc2cd74755 | ||
|
4ab4393632 | ||
|
f352fa0cab | ||
|
9ee937a429 | ||
|
cf01543f06 | ||
|
bbdfe28449 | ||
|
d87cbe3210 | ||
|
afc5a44446 | ||
|
e0b3049bff | ||
|
217df48c45 | ||
|
a03b87785f | ||
|
b35193b3df | ||
|
ec38091599 | ||
|
3eae2e4fdc | ||
|
8bbf56d2f4 | ||
|
23c4006979 | ||
|
268ccb00a8 | ||
|
17bbe50320 | ||
|
471c5801f1 | ||
|
ddecccec86 | ||
|
17267ed4b1 | ||
|
1f120b821d | ||
|
e3ace324ee | ||
|
1cbd3393c8 | ||
|
a4e38090b0 | ||
|
82a89b2c03 | ||
|
8fb214c322 | ||
|
63088afd87 | ||
|
02369442a2 | ||
|
68df5a64a3 | ||
|
fc579533e8 | ||
|
9b85fac61b | ||
|
227be5480e | ||
|
c0f1a8eadf | ||
|
7773e31c47 | ||
|
abf7778395 | ||
|
cec9d67165 | ||
|
a535e8a577 | ||
|
a1b6dc0598 | ||
|
0f0bc32a42 | ||
|
7b18f346dd | ||
|
f5f7f3664c | ||
|
7cf24f5370 | ||
|
0e09dfe1b2 | ||
|
f410b0f969 | ||
|
0e60013311 | ||
|
4160a6a580 | ||
|
52c7a56f68 | ||
|
cb430456bf | ||
|
434a350819 | ||
|
03567dbe66 | ||
|
f90427229d | ||
|
4745d61905 | ||
|
f3a6aba4c4 | ||
|
fe56c5c84c | ||
|
5b43099d78 | ||
|
59a6f298ee | ||
|
feb74c3299 | ||
|
72116d01c0 | ||
|
df3f832762 | ||
|
5d08b128d2 | ||
|
31fe6c7620 | ||
|
4381bc6103 | ||
|
589dbd5719 | ||
|
a4a8ebba76 | ||
|
bb8e4a9746 | ||
|
926c65dd14 | ||
|
0114a72fa5 | ||
|
80b85cbf19 | ||
|
7bae8e040c | ||
|
9045fc6cc0 | ||
|
12029c768c | ||
|
71ba5fe582 | ||
|
804a55ba64 | ||
|
9bd71281b9 | ||
|
a2484fdb5f | ||
|
d549840eed | ||
|
bf8632c063 | ||
|
71ce2a07b2 | ||
|
eb2d7c36f5 | ||
|
ee3a256206 | ||
|
62d80d40da | ||
|
83869461ab | ||
|
a73c535ca2 | ||
|
2d932da1f3 | ||
|
cd1cc09b39 | ||
|
323245154a | ||
|
2bbfcb010c | ||
|
0b49227ade | ||
|
c6bc06d036 | ||
|
84774fd936 | ||
|
635605e0c9 | ||
|
9cd5022698 | ||
|
7531190e7d | ||
|
d87c905246 | ||
|
892122b45e | ||
|
9c5818bb16 | ||
|
dd0efa2410 | ||
|
cda0018a29 | ||
|
4b34fe546d | ||
|
c0a5cd0c0f | ||
|
1100cead24 | ||
|
d6909fe9b6 | ||
|
ba0779b415 | ||
|
80a2d57f62 | ||
|
1dddafd4b3 | ||
|
1a6d2142b0 | ||
|
57e24c7465 | ||
|
40200bca12 | ||
|
d648ce133e | ||
|
5557acd7d8 | ||
|
95290abb94 | ||
|
5138a49591 | ||
|
0184dc991c | ||
|
1f54d73f8c | ||
|
95e5ee2496 | ||
|
36c26595a0 | ||
|
3cf145a3cc | ||
|
c5dfbe7924 | ||
|
867f507fac | ||
|
f729dd58b7 | ||
|
4a7bacb270 | ||
|
2024c1898b | ||
|
b7ec76e091 | ||
|
645b50538a | ||
|
4cf6b4f37b | ||
|
61a1e98403 | ||
|
b4ff22815e | ||
|
5ce5c0eb41 | ||
|
ed015f3cf3 | ||
|
a1253050fe | ||
|
d1add47500 | ||
|
108a40a31c | ||
|
7c0e327518 | ||
|
1b1bad423e | ||
|
12fe8bf29c | ||
|
5497248d40 | ||
|
2b21053fca | ||
|
1444ff1aaf | ||
|
4c79001b12 | ||
|
8c05b4da6a | ||
|
5fd8edf0be | ||
|
2443560c1d | ||
|
02d87ae550 | ||
|
bf6f3cb785 | ||
|
49190d04dd | ||
|
e0750a7b68 | ||
|
41e3ccf692 | ||
|
2d33206d29 | ||
|
6d8e5976f7 | ||
|
788397f60c | ||
|
9eed1e3fd4 | ||
|
f6c429f00c | ||
|
cc49cbcdd1 | ||
|
89c54dba8d | ||
|
b8317ac4f2 | ||
|
d36951da88 | ||
|
8283ee9f29 | ||
|
41f46631a7 | ||
|
48384557a5 | ||
|
cb9ecc4b43 | ||
|
407e558b60 | ||
|
f3d731c599 | ||
|
87bd80b72c | ||
|
129819314d | ||
|
6a63d1f431 | ||
|
8f7cc0d20e | ||
|
b429c74bcf | ||
|
d62e9f6560 | ||
|
d94eb48978 | ||
|
2e788a8a1a | ||
|
1f0a80d035 |
418
.github/workflows/main.yml
vendored
Normal file
|
@ -0,0 +1,418 @@
|
|||
name: CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
# Release builds
|
||||
build_release_macos:
|
||||
name: Release build (macOS universal, static Qt 6.5.0)
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get Qt
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: LongSoft/qt-6-static-universal-macos
|
||||
path: qt
|
||||
lfs: true
|
||||
- name: Unpack Qt
|
||||
shell: bash
|
||||
working-directory: qt
|
||||
run: sudo 7z x qt-6.5.0-static-universal-macos.7z -o/opt
|
||||
- name: Create build directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Configure everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake -DCMAKE_PREFIX_PATH="/opt/qt-6.5.0-static-universal-macos" -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="11.0" ../UEFITool
|
||||
- name: Build everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config Release
|
||||
- name: Create dist directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/UEFITool/dist
|
||||
- name: Signed archive everything
|
||||
if: github.repository_owner == 'LongSoft'
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
env:
|
||||
MAC_CERTIFICATE_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
|
||||
MAC_ACCOUNT_NAME: ${{ secrets.MAC_ACCOUNT_NAME }}
|
||||
MAC_ACCOUNT_PASSWORD: ${{ secrets.MAC_ACCOUNT_PASSWORD }}
|
||||
shell: bash
|
||||
run: |
|
||||
UEFITOOL_VER=$(cat ../UEFITool/version.h | grep PROGRAM_VERSION | cut -d'"' -f2 | sed 's/NE alpha /A/') ; \
|
||||
codesign -fs - UEFIExtract/UEFIExtract
|
||||
codesign -fs - UEFIFind/UEFIFind
|
||||
zip -qryj ../UEFITool/dist/UEFIExtract_NE_${UEFITOOL_VER}_universal_mac.zip ./UEFIExtract/UEFIExtract
|
||||
zip -qryj ../UEFITool/dist/UEFIFind_NE_${UEFITOOL_VER}_universal_mac.zip ./UEFIFind/UEFIFind
|
||||
brew install create-dmg || exit 1
|
||||
curl -OL "https://github.com/acidanthera/ocbuild/raw/master/codesign/appsign.sh" || exit 1
|
||||
chmod a+x appsign.sh || exit 1
|
||||
"$(pwd)/appsign.sh" ./UEFITool/UEFITool.app ../UEFITool/dist/UEFITool_NE_${UEFITOOL_VER}_universal_mac.dmg
|
||||
- name: Archive everything
|
||||
if: github.repository_owner != 'LongSoft'
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: |
|
||||
UEFITOOL_VER=$(cat ../UEFITool/version.h | grep PROGRAM_VERSION | cut -d'"' -f2 | sed 's/NE alpha /A/') ; \
|
||||
codesign -fs - UEFIExtract/UEFIExtract
|
||||
codesign -fs - UEFIFind/UEFIFind
|
||||
zip -qryj ../UEFITool/dist/UEFIExtract_NE_${UEFITOOL_VER}_universal_mac.zip ./UEFIExtract/UEFIExtract
|
||||
zip -qryj ../UEFITool/dist/UEFIFind_NE_${UEFITOOL_VER}_universal_mac.zip ./UEFIFind/UEFIFind
|
||||
cd UEFITool
|
||||
codesign -fs - --deep UEFITool.app
|
||||
zip -qry ../../UEFITool/dist/UEFITool_NE_${UEFITOOL_VER}_universal_mac.zip ./UEFITool.app
|
||||
- name: Upload to artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macOS builds
|
||||
path: dist/*
|
||||
- name: Upload to releases
|
||||
if: github.event_name == 'release'
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: dist/*
|
||||
tag: ${{ github.ref }}
|
||||
file_glob: true
|
||||
|
||||
build_release_linux:
|
||||
name: Release build (Linux x64, shared Qt 6)
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get Qt
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install -qq zip cmake libgl1-mesa-dev qt6-base-dev
|
||||
- name: Create build directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Configure everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake ../UEFITool
|
||||
- name: Build everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config Release
|
||||
- name: Create dist directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/UEFITool/dist
|
||||
- name: Archive everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: |
|
||||
UEFITOOL_VER=$(cat ../UEFITool/version.h | grep PROGRAM_VERSION | cut -d'"' -f2 | sed 's/NE alpha /A/') ; \
|
||||
zip -qryj ../UEFITool/dist/UEFIExtract_NE_${UEFITOOL_VER}_x64_linux.zip ./UEFIExtract/uefiextract
|
||||
zip -qryj ../UEFITool/dist/UEFIFind_NE_${UEFITOOL_VER}_x64_linux.zip ./UEFIFind/uefifind
|
||||
zip -qryj ../UEFITool/dist/UEFITool_NE_${UEFITOOL_VER}_x64_linux.zip ./UEFITool/uefitool
|
||||
- name: Upload to artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Linux builds
|
||||
path: dist/*.zip
|
||||
- name: Upload to releases
|
||||
if: github.event_name == 'release'
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: dist/*.zip
|
||||
tag: ${{ github.ref }}
|
||||
file_glob: true
|
||||
|
||||
build_release_freebsd:
|
||||
name: Release build (FreeBSD x64, shared Qt 6)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build on FreeBSD inside Ubuntu VM
|
||||
id: test
|
||||
uses: cross-platform-actions/action@v0.27.0
|
||||
with:
|
||||
operating_system: freebsd
|
||||
version: '13.3'
|
||||
shell: sh
|
||||
run: |
|
||||
sudo pkg install -y zip cmake qt6-base
|
||||
mkdir dist
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
UEFITOOL_VER=$(cat ../version.h | grep PROGRAM_VERSION | cut -d'"' -f2 | sed 's/NE alpha /A/') ; \
|
||||
zip -qryj ../dist/UEFIExtract_NE_${UEFITOOL_VER}_x64_freebsd.zip ./UEFIExtract/uefiextract
|
||||
zip -qryj ../dist/UEFIFind_NE_${UEFITOOL_VER}_x64_freebsd.zip ./UEFIFind/uefifind
|
||||
zip -qryj ../dist/UEFITool_NE_${UEFITOOL_VER}_x64_freebsd.zip ./UEFITool/uefitool
|
||||
- name: Upload to artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: FreeBSD builds
|
||||
path: dist/*.zip
|
||||
- name: Upload to releases
|
||||
if: github.event_name == 'release'
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: dist/*.zip
|
||||
tag: ${{ github.ref }}
|
||||
file_glob: true
|
||||
|
||||
build_release_windows_32:
|
||||
name: Release build (Win32, static Qt 5.6.3)
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get Qt 5.6.3
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: LongSoft/qt-5.6.3-static-x86-msvc2017
|
||||
path: qt5
|
||||
lfs: true
|
||||
- name: Unpack Qt 5.6.3
|
||||
shell: bash
|
||||
working-directory: qt5
|
||||
run: 7z x qt-5.6.3-static-x86-msvc2017.7z -o../..
|
||||
- name: Create dist directory
|
||||
shell: bash
|
||||
run: mkdir dist
|
||||
- name: Create UEFIExtract build directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build/UEFIExtract
|
||||
- name: Configure UEFIExtract
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build/UEFIExtract
|
||||
run: cmake -G "Visual Studio 16 2019" -A Win32 -T "v141_xp" -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded" ../../UEFITool/UEFIExtract/
|
||||
- name: Build UEFIExtract
|
||||
working-directory: ${{runner.workspace}}/build/UEFIExtract
|
||||
shell: bash
|
||||
run: cmake --build . --config Release
|
||||
- name: Archive UEFIExtract
|
||||
working-directory: ${{runner.workspace}}/build/UEFIExtract/Release
|
||||
shell: bash
|
||||
run: |
|
||||
UEFITOOL_VER=$(cat ../../../UEFITool/version.h | grep PROGRAM_VERSION | cut -d'"' -f2 | sed 's/NE alpha /A/') ; \
|
||||
7z a ../../../UEFITool/dist/UEFIExtract_NE_${UEFITOOL_VER}_win32.zip UEFIExtract.exe
|
||||
- name: Create UEFIFind build directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build/UEFIFind
|
||||
- name: Configure UEFIFind
|
||||
working-directory: ${{runner.workspace}}/build/UEFIFind
|
||||
shell: bash
|
||||
run: cmake -G "Visual Studio 16 2019" -A Win32 -T "v141_xp" -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded" ../../UEFITool/UEFIFind/
|
||||
- name: Build UEFIFind
|
||||
working-directory: ${{runner.workspace}}/build/UEFIFind
|
||||
shell: bash
|
||||
run: cmake --build . --config Release
|
||||
- name: Archive UEFIFind
|
||||
working-directory: ${{runner.workspace}}/build/UEFIFind/Release
|
||||
shell: bash
|
||||
run: |
|
||||
UEFITOOL_VER=$(cat ../../../UEFITool/version.h | grep PROGRAM_VERSION | cut -d'"' -f2 | sed 's/NE alpha /A/') ; \
|
||||
7z a ../../../UEFITool/dist/UEFIFind_NE_${UEFITOOL_VER}_win32.zip UEFIFind.exe
|
||||
- name: Create UEFITool build directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build/UEFITool
|
||||
- name: Configure UEFITool
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build/UEFITool
|
||||
run: ../../qt-5.6.3-static-x86-msvc2017/bin/qmake.exe -tp vc ../../UEFITool/UEFITool/
|
||||
- name: Build UEFITool
|
||||
working-directory: ${{runner.workspace}}/build/UEFITool
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars32.bat"
|
||||
msbuild -t:Rebuild -p:PlatformToolset=v141_xp;Configuration=Release
|
||||
- name: Archive UEFITool
|
||||
working-directory: ${{runner.workspace}}/build/UEFITool/release
|
||||
shell: bash
|
||||
run: |
|
||||
UEFITOOL_VER=$(cat ../../../UEFITool/version.h | grep PROGRAM_VERSION | cut -d'"' -f2 | sed 's/NE alpha /A/') ; \
|
||||
7z a ../../../UEFITool/dist/UEFITool_NE_${UEFITOOL_VER}_win32.zip UEFITool.exe
|
||||
- name: Upload to artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows 32-bit builds
|
||||
path: dist/*.zip
|
||||
- name: Upload to releases
|
||||
if: github.event_name == 'release'
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: dist/*.zip
|
||||
tag: ${{ github.ref }}
|
||||
file_glob: true
|
||||
|
||||
build_release_windows_64:
|
||||
name: Release build (Win64, static Qt 6.5.0)
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get Qt 6.5.0
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: LongSoft/qt-6-static-x64-msvc2022
|
||||
path: qt6
|
||||
lfs: true
|
||||
- name: Unpack Qt 6.5.0
|
||||
shell: bash
|
||||
working-directory: qt6
|
||||
run: 7z x qt-6.5.0-static-x64-msvc2022.7z -o../..
|
||||
- name: Create build directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Configure everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: cmd
|
||||
run: cmake -DCMAKE_PREFIX_PATH="D:\a\UEFITool\qt-6.5.0-static-x64-msvc2022" -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded" -A x64 ../UEFITool
|
||||
- name: Build everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config Release
|
||||
- name: Create dist directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/UEFITool/dist
|
||||
- name: Archive everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: |
|
||||
UEFITOOL_VER=$(cat ../UEFITool/version.h | grep PROGRAM_VERSION | cut -d'"' -f2 | sed 's/NE alpha /A/') ; \
|
||||
7z a ../UEFITool/dist/UEFIExtract_NE_${UEFITOOL_VER}_win64.zip ./UEFIExtract/Release/UEFIExtract.exe
|
||||
7z a ../UEFITool/dist/UEFIFind_NE_${UEFITOOL_VER}_win64.zip ./UEFIFind/Release/UEFIFind.exe
|
||||
7z a ../UEFITool/dist/UEFITool_NE_${UEFITOOL_VER}_win64.zip ./UEFITool/Release/UEFITool.exe
|
||||
- name: Upload to artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows 64-bit builds
|
||||
path: dist/*.zip
|
||||
- name: Upload to releases
|
||||
if: github.event_name == 'release'
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: dist/*.zip
|
||||
tag: ${{ github.ref }}
|
||||
file_glob: true
|
||||
|
||||
# Build Tests
|
||||
build_test_linux_meson:
|
||||
name: Meson build system test (shared Qt 5)
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get Deps
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install -qq cmake meson zlib1g-dev qtbase5-dev
|
||||
- name: Configure build
|
||||
run: mkdir build-meson && meson ./build-meson
|
||||
- name: Build everything
|
||||
run: ninja -C build-meson
|
||||
|
||||
build_test_windows_mingw:
|
||||
name: MinGW compiler test (shared Qt 6.5.0)
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '6.5.0'
|
||||
host: 'windows'
|
||||
target: 'desktop'
|
||||
arch: 'win64_mingw'
|
||||
- name: Build everything
|
||||
run: |
|
||||
cmake -G "MinGW Makefiles" -B build .
|
||||
cmake --build build --parallel
|
||||
|
||||
build_test_linux_fuzzer:
|
||||
name: Fuzzer build test (Clang, Linux x64)
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Create build directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Configure everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake ../UEFITool/fuzzing
|
||||
- name: Build everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build .
|
||||
- name: Create dist directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/dist
|
||||
- name: Archive everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: |
|
||||
UEFITOOL_VER=$(cat ../UEFITool/version.h | grep PROGRAM_VERSION | cut -d'"' -f2 | sed 's/NE alpha /A/') ; \
|
||||
zip -qryj ../dist/ffsparser_fuzzer_NE_${UEFITOOL_VER}_x64_linux.zip ./ffsparser_fuzzer
|
||||
- name: Upload to artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Fuzzer
|
||||
path: ${{runner.workspace}}/dist/*.zip
|
||||
|
||||
# Static Analysis
|
||||
build_analyze_linux_coverity:
|
||||
env:
|
||||
PROJECT_TYPE: TOOL
|
||||
JOB_TYPE: COVERITY
|
||||
if: github.repository_owner == 'LongSoft' && github.event_name != 'pull_request'
|
||||
name: Coverity Static Analysis (shared Qt 6.5.0)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '6.5.0'
|
||||
host: 'linux'
|
||||
target: 'desktop'
|
||||
- name: Create build directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Configure everything
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake ../UEFITool
|
||||
- name: Run Coverity
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: |
|
||||
src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/coverity/covstrap-linux.sh) && eval "$src" || exit 1
|
||||
env:
|
||||
COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
COVERITY_SCAN_EMAIL: ${{ secrets.COVERITY_SCAN_EMAIL }}
|
||||
COVERITY_BUILD_COMMAND: cmake --build .
|
||||
|
||||
build_analyze_linux_sonarcloud:
|
||||
if: github.repository_owner == 'LongSoft' && github.event_name != 'pull_request'
|
||||
name: SonarCloud Static Analysis (shared Qt 6.5.0)
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '6.5.0'
|
||||
host: 'linux'
|
||||
target: 'desktop'
|
||||
- name: Install JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
- name: Install build-wrapper
|
||||
uses: SonarSource/sonarcloud-github-c-cpp@v2
|
||||
- name: Run build-wrapper
|
||||
run: |
|
||||
cmake -B build .
|
||||
build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build
|
||||
- name: SonarQube Scan
|
||||
uses: SonarSource/sonarqube-scan-action@v4.2.1
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_ROOT_CERT: ${{ secrets.SONAR_ROOT_CERT }}
|
||||
with:
|
||||
# Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options
|
||||
args: >
|
||||
--define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json"
|
22
.gitignore
vendored
|
@ -3,6 +3,7 @@
|
|||
#################
|
||||
moc_*.*
|
||||
ui_*.*
|
||||
qrc_*.*
|
||||
|
||||
#################
|
||||
## Qt Creator
|
||||
|
@ -186,6 +187,7 @@ ehthumbs.db
|
|||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
.directory
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
@ -230,7 +232,23 @@ pip-log.txt
|
|||
#############
|
||||
*.o
|
||||
Makefile
|
||||
|
||||
uefitool_plugin_import.cpp
|
||||
UEFITool.app/
|
||||
UEFITool/XCBuildData
|
||||
UEFIDump/UEFIDump
|
||||
UEFIExtract/UEFIExtract
|
||||
UEFIExtract/guids.csv
|
||||
UEFIFind/UEFIFind
|
||||
UEFIPatch/UEFIPatch
|
||||
UEFITool
|
||||
.qmake.stash
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
cmake_install.cmake
|
||||
DerivedData
|
||||
*.xcodeproj
|
||||
compile_commands.json
|
||||
CMakeScripts
|
||||
UEFITool/qrc_uefitool.cpp
|
||||
XcodeQT5
|
||||
XcodeQT6
|
||||
*.dSYM
|
||||
|
|
14
.travis.yml
|
@ -1,14 +0,0 @@
|
|||
language: cpp
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository --yes ppa:ubuntu-sdk-team/ppa
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq qt5-qmake qtbase5-dev qtdeclarative5-dev libqt5webkit5-dev libsqlite3-dev
|
||||
|
||||
script:
|
||||
- qmake -qt=qt5 uefitool.pro
|
||||
- make
|
7
CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 3.22)
|
||||
|
||||
PROJECT(UEFITool_everything)
|
||||
|
||||
ADD_SUBDIRECTORY(UEFIExtract)
|
||||
ADD_SUBDIRECTORY(UEFIFind)
|
||||
ADD_SUBDIRECTORY(UEFITool)
|
|
@ -1,7 +0,0 @@
|
|||
#define MY_VER_MAJOR 9
|
||||
#define MY_VER_MINOR 20
|
||||
#define MY_VER_BUILD 0
|
||||
#define MY_VERSION "9.20"
|
||||
#define MY_DATE "2010-11-18"
|
||||
#define MY_COPYRIGHT ": Igor Pavlov : Public domain"
|
||||
#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE
|
|
@ -1,68 +0,0 @@
|
|||
/* Bra.h -- Branch converters for executables
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BRA_H
|
||||
#define __BRA_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
These functions convert relative addresses to absolute addresses
|
||||
in CALL instructions to increase the compression ratio.
|
||||
|
||||
In:
|
||||
data - data buffer
|
||||
size - size of data
|
||||
ip - current virtual Instruction Pinter (IP) value
|
||||
state - state variable for x86 converter
|
||||
encoding - 0 (for decoding), 1 (for encoding)
|
||||
|
||||
Out:
|
||||
state - state variable for x86 converter
|
||||
|
||||
Returns:
|
||||
The number of processed bytes. If you call these functions with multiple calls,
|
||||
you must start next call with first byte after block of processed bytes.
|
||||
|
||||
Type Endian Alignment LookAhead
|
||||
|
||||
x86 little 1 4
|
||||
ARMT little 2 2
|
||||
ARM little 4 0
|
||||
PPC big 4 0
|
||||
SPARC big 4 0
|
||||
IA64 little 16 0
|
||||
|
||||
size must be >= Alignment + LookAhead, if it's not last block.
|
||||
If (size < Alignment + LookAhead), converter returns 0.
|
||||
|
||||
Example:
|
||||
|
||||
UInt32 ip = 0;
|
||||
for ()
|
||||
{
|
||||
; size must be >= Alignment + LookAhead, if it's not last block
|
||||
SizeT processed = Convert(data, size, ip, 1);
|
||||
data += processed;
|
||||
size -= processed;
|
||||
ip += processed;
|
||||
}
|
||||
*/
|
||||
|
||||
#define x86_Convert_Init(state) { state = 0; }
|
||||
SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
|
||||
SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,85 +0,0 @@
|
|||
/* Bra86.c -- Converter for x86 code (BCJ)
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Bra.h"
|
||||
|
||||
#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
|
||||
|
||||
const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
|
||||
const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
|
||||
|
||||
SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
|
||||
{
|
||||
SizeT bufferPos = 0, prevPosT;
|
||||
UInt32 prevMask = *state & 0x7;
|
||||
if (size < 5)
|
||||
return 0;
|
||||
ip += 5;
|
||||
prevPosT = (SizeT)0 - 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte *p = data + bufferPos;
|
||||
Byte *limit = data + size - 4;
|
||||
for (; p < limit; p++)
|
||||
if ((*p & 0xFE) == 0xE8)
|
||||
break;
|
||||
bufferPos = (SizeT)(p - data);
|
||||
if (p >= limit)
|
||||
break;
|
||||
prevPosT = bufferPos - prevPosT;
|
||||
if (prevPosT > 3)
|
||||
prevMask = 0;
|
||||
else
|
||||
{
|
||||
prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
|
||||
if (prevMask != 0)
|
||||
{
|
||||
Byte b = p[4 - kMaskToBitNumber[prevMask]];
|
||||
if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
|
||||
{
|
||||
prevPosT = bufferPos;
|
||||
prevMask = ((prevMask << 1) & 0x7) | 1;
|
||||
bufferPos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
prevPosT = bufferPos;
|
||||
|
||||
if (Test86MSByte(p[4]))
|
||||
{
|
||||
UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
|
||||
UInt32 dest;
|
||||
for (;;)
|
||||
{
|
||||
Byte b;
|
||||
int index;
|
||||
if (encoding)
|
||||
dest = (ip + (UInt32)bufferPos) + src;
|
||||
else
|
||||
dest = src - (ip + (UInt32)bufferPos);
|
||||
if (prevMask == 0)
|
||||
break;
|
||||
index = kMaskToBitNumber[prevMask] * 8;
|
||||
b = (Byte)(dest >> (24 - index));
|
||||
if (!Test86MSByte(b))
|
||||
break;
|
||||
src = dest ^ ((1 << (32 - index)) - 1);
|
||||
}
|
||||
p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
|
||||
p[3] = (Byte)(dest >> 16);
|
||||
p[2] = (Byte)(dest >> 8);
|
||||
p[1] = (Byte)dest;
|
||||
bufferPos += 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevMask = ((prevMask << 1) & 0x7) | 1;
|
||||
bufferPos++;
|
||||
}
|
||||
}
|
||||
prevPosT = bufferPos - prevPosT;
|
||||
*state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
|
||||
return bufferPos;
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
/* CpuArch.h -- CPU specific code
|
||||
2010-10-26: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __CPU_ARCH_H
|
||||
#define __CPU_ARCH_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
/*
|
||||
MY_CPU_LE means that CPU is LITTLE ENDIAN.
|
||||
If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN).
|
||||
|
||||
MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
|
||||
If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform.
|
||||
*/
|
||||
|
||||
#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
|
||||
#define MY_CPU_AMD64
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_AMD64) || defined(_M_IA64)
|
||||
#define MY_CPU_64BIT
|
||||
#endif
|
||||
|
||||
#if defined(_M_IX86) || defined(__i386__)
|
||||
#define MY_CPU_X86
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
|
||||
#define MY_CPU_X86_OR_AMD64
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86) || defined(_M_ARM)
|
||||
#define MY_CPU_32BIT
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_ARM)
|
||||
#define MY_CPU_ARM_LE
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_IA64)
|
||||
#define MY_CPU_IA64_LE
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86_OR_AMD64)
|
||||
#define MY_CPU_LE_UNALIGN
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__)
|
||||
#define MY_CPU_LE
|
||||
#endif
|
||||
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
#define MY_CPU_BE
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
|
||||
Stop_Compiling_Bad_Endian
|
||||
#endif
|
||||
|
||||
#ifdef MY_CPU_LE_UNALIGN
|
||||
|
||||
#define GetUi16(p) (*(const UInt16 *)(p))
|
||||
#define GetUi32(p) (*(const UInt32 *)(p))
|
||||
#define GetUi64(p) (*(const UInt64 *)(p))
|
||||
#define SetUi16(p, d) *(UInt16 *)(p) = (d);
|
||||
#define SetUi32(p, d) *(UInt32 *)(p) = (d);
|
||||
#define SetUi64(p, d) *(UInt64 *)(p) = (d);
|
||||
|
||||
#else
|
||||
|
||||
#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8))
|
||||
|
||||
#define GetUi32(p) ( \
|
||||
((const Byte *)(p))[0] | \
|
||||
((UInt32)((const Byte *)(p))[1] << 8) | \
|
||||
((UInt32)((const Byte *)(p))[2] << 16) | \
|
||||
((UInt32)((const Byte *)(p))[3] << 24))
|
||||
|
||||
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
|
||||
|
||||
#define SetUi16(p, d) { UInt32 _x_ = (d); \
|
||||
((Byte *)(p))[0] = (Byte)_x_; \
|
||||
((Byte *)(p))[1] = (Byte)(_x_ >> 8); }
|
||||
|
||||
#define SetUi32(p, d) { UInt32 _x_ = (d); \
|
||||
((Byte *)(p))[0] = (Byte)_x_; \
|
||||
((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
|
||||
((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
|
||||
((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
|
||||
|
||||
#define SetUi64(p, d) { UInt64 _x64_ = (d); \
|
||||
SetUi32(p, (UInt32)_x64_); \
|
||||
SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
|
||||
|
||||
#pragma intrinsic(_byteswap_ulong)
|
||||
#pragma intrinsic(_byteswap_uint64)
|
||||
#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
|
||||
#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
|
||||
|
||||
#else
|
||||
|
||||
#define GetBe32(p) ( \
|
||||
((UInt32)((const Byte *)(p))[0] << 24) | \
|
||||
((UInt32)((const Byte *)(p))[1] << 16) | \
|
||||
((UInt32)((const Byte *)(p))[2] << 8) | \
|
||||
((const Byte *)(p))[3] )
|
||||
|
||||
#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
|
||||
|
||||
#endif
|
||||
|
||||
#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])
|
||||
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 maxFunc;
|
||||
UInt32 vendor[3];
|
||||
UInt32 ver;
|
||||
UInt32 b;
|
||||
UInt32 c;
|
||||
UInt32 d;
|
||||
} Cx86cpuid;
|
||||
|
||||
enum
|
||||
{
|
||||
CPU_FIRM_INTEL,
|
||||
CPU_FIRM_AMD,
|
||||
CPU_FIRM_VIA
|
||||
};
|
||||
|
||||
Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
|
||||
int x86cpuid_GetFirm(const Cx86cpuid *p);
|
||||
|
||||
#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F)
|
||||
#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F)
|
||||
#define x86cpuid_GetStepping(p) ((p)->ver & 0xF)
|
||||
|
||||
Bool CPU_Is_InOrder();
|
||||
Bool CPU_Is_Aes_Supported();
|
||||
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
|
@ -1,754 +0,0 @@
|
|||
/* LzFind.c -- Match finder for LZ algorithms
|
||||
2009-04-22 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "LzFind.h"
|
||||
#include "LzHash.h"
|
||||
|
||||
#define kEmptyHashValue 0
|
||||
#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
|
||||
#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
|
||||
#define kNormalizeMask (~(kNormalizeStepMin - 1))
|
||||
#define kMaxHistorySize ((UInt32)3 << 30)
|
||||
|
||||
#define kStartMaxLen 3
|
||||
|
||||
static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
|
||||
{
|
||||
if (!p->directInput)
|
||||
{
|
||||
alloc->Free(alloc, p->bufferBase);
|
||||
p->bufferBase = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
|
||||
|
||||
static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
|
||||
{
|
||||
UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
|
||||
if (p->directInput)
|
||||
{
|
||||
p->blockSize = blockSize;
|
||||
return 1;
|
||||
}
|
||||
if (p->bufferBase == 0 || p->blockSize != blockSize)
|
||||
{
|
||||
LzInWindow_Free(p, alloc);
|
||||
p->blockSize = blockSize;
|
||||
p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
|
||||
}
|
||||
return (p->bufferBase != 0);
|
||||
}
|
||||
|
||||
Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
|
||||
Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
|
||||
|
||||
UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
|
||||
|
||||
void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
|
||||
{
|
||||
p->posLimit -= subValue;
|
||||
p->pos -= subValue;
|
||||
p->streamPos -= subValue;
|
||||
}
|
||||
|
||||
static void MatchFinder_ReadBlock(CMatchFinder *p)
|
||||
{
|
||||
if (p->streamEndWasReached || p->result != SZ_OK)
|
||||
return;
|
||||
if (p->directInput)
|
||||
{
|
||||
UInt32 curSize = 0xFFFFFFFF - p->streamPos;
|
||||
if (curSize > p->directInputRem)
|
||||
curSize = (UInt32)p->directInputRem;
|
||||
p->directInputRem -= curSize;
|
||||
p->streamPos += curSize;
|
||||
if (p->directInputRem == 0)
|
||||
p->streamEndWasReached = 1;
|
||||
return;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
Byte *dest = p->buffer + (p->streamPos - p->pos);
|
||||
size_t size = (p->bufferBase + p->blockSize - dest);
|
||||
if (size == 0)
|
||||
return;
|
||||
p->result = p->stream->Read(p->stream, dest, &size);
|
||||
if (p->result != SZ_OK)
|
||||
return;
|
||||
if (size == 0)
|
||||
{
|
||||
p->streamEndWasReached = 1;
|
||||
return;
|
||||
}
|
||||
p->streamPos += (UInt32)size;
|
||||
if (p->streamPos - p->pos > p->keepSizeAfter)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MatchFinder_MoveBlock(CMatchFinder *p)
|
||||
{
|
||||
memmove(p->bufferBase,
|
||||
p->buffer - p->keepSizeBefore,
|
||||
(size_t)(p->streamPos - p->pos + p->keepSizeBefore));
|
||||
p->buffer = p->bufferBase + p->keepSizeBefore;
|
||||
}
|
||||
|
||||
int MatchFinder_NeedMove(CMatchFinder *p)
|
||||
{
|
||||
if (p->directInput)
|
||||
return 0;
|
||||
/* if (p->streamEndWasReached) return 0; */
|
||||
return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
|
||||
}
|
||||
|
||||
void MatchFinder_ReadIfRequired(CMatchFinder *p)
|
||||
{
|
||||
if (p->streamEndWasReached)
|
||||
return;
|
||||
if (p->keepSizeAfter >= p->streamPos - p->pos)
|
||||
MatchFinder_ReadBlock(p);
|
||||
}
|
||||
|
||||
static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
|
||||
{
|
||||
if (MatchFinder_NeedMove(p))
|
||||
MatchFinder_MoveBlock(p);
|
||||
MatchFinder_ReadBlock(p);
|
||||
}
|
||||
|
||||
static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
|
||||
{
|
||||
p->cutValue = 32;
|
||||
p->btMode = 1;
|
||||
p->numHashBytes = 4;
|
||||
p->bigHash = 0;
|
||||
}
|
||||
|
||||
#define kCrcPoly 0xEDB88320
|
||||
|
||||
void MatchFinder_Construct(CMatchFinder *p)
|
||||
{
|
||||
UInt32 i;
|
||||
p->bufferBase = 0;
|
||||
p->directInput = 0;
|
||||
p->hash = 0;
|
||||
MatchFinder_SetDefaultSettings(p);
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = i;
|
||||
int j;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
p->crc[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, p->hash);
|
||||
p->hash = 0;
|
||||
}
|
||||
|
||||
void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
|
||||
{
|
||||
MatchFinder_FreeThisClassMemory(p, alloc);
|
||||
LzInWindow_Free(p, alloc);
|
||||
}
|
||||
|
||||
static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
|
||||
{
|
||||
size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
|
||||
if (sizeInBytes / sizeof(CLzRef) != num)
|
||||
return 0;
|
||||
return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
|
||||
}
|
||||
|
||||
int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
|
||||
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
|
||||
ISzAlloc *alloc)
|
||||
{
|
||||
UInt32 sizeReserv;
|
||||
if (historySize > kMaxHistorySize)
|
||||
{
|
||||
MatchFinder_Free(p, alloc);
|
||||
return 0;
|
||||
}
|
||||
sizeReserv = historySize >> 1;
|
||||
if (historySize > ((UInt32)2 << 30))
|
||||
sizeReserv = historySize >> 2;
|
||||
sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
|
||||
|
||||
p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
|
||||
p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
|
||||
/* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
|
||||
if (LzInWindow_Create(p, sizeReserv, alloc))
|
||||
{
|
||||
UInt32 newCyclicBufferSize = historySize + 1;
|
||||
UInt32 hs;
|
||||
p->matchMaxLen = matchMaxLen;
|
||||
{
|
||||
p->fixedHashSize = 0;
|
||||
if (p->numHashBytes == 2)
|
||||
hs = (1 << 16) - 1;
|
||||
else
|
||||
{
|
||||
hs = historySize - 1;
|
||||
hs |= (hs >> 1);
|
||||
hs |= (hs >> 2);
|
||||
hs |= (hs >> 4);
|
||||
hs |= (hs >> 8);
|
||||
hs >>= 1;
|
||||
hs |= 0xFFFF; /* don't change it! It's required for Deflate */
|
||||
if (hs > (1 << 24))
|
||||
{
|
||||
if (p->numHashBytes == 3)
|
||||
hs = (1 << 24) - 1;
|
||||
else
|
||||
hs >>= 1;
|
||||
}
|
||||
}
|
||||
p->hashMask = hs;
|
||||
hs++;
|
||||
if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
|
||||
if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
|
||||
if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
|
||||
hs += p->fixedHashSize;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 prevSize = p->hashSizeSum + p->numSons;
|
||||
UInt32 newSize;
|
||||
p->historySize = historySize;
|
||||
p->hashSizeSum = hs;
|
||||
p->cyclicBufferSize = newCyclicBufferSize;
|
||||
p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
|
||||
newSize = p->hashSizeSum + p->numSons;
|
||||
if (p->hash != 0 && prevSize == newSize)
|
||||
return 1;
|
||||
MatchFinder_FreeThisClassMemory(p, alloc);
|
||||
p->hash = AllocRefs(newSize, alloc);
|
||||
if (p->hash != 0)
|
||||
{
|
||||
p->son = p->hash + p->hashSizeSum;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
MatchFinder_Free(p, alloc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void MatchFinder_SetLimits(CMatchFinder *p)
|
||||
{
|
||||
UInt32 limit = kMaxValForNormalize - p->pos;
|
||||
UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
|
||||
if (limit2 < limit)
|
||||
limit = limit2;
|
||||
limit2 = p->streamPos - p->pos;
|
||||
if (limit2 <= p->keepSizeAfter)
|
||||
{
|
||||
if (limit2 > 0)
|
||||
limit2 = 1;
|
||||
}
|
||||
else
|
||||
limit2 -= p->keepSizeAfter;
|
||||
if (limit2 < limit)
|
||||
limit = limit2;
|
||||
{
|
||||
UInt32 lenLimit = p->streamPos - p->pos;
|
||||
if (lenLimit > p->matchMaxLen)
|
||||
lenLimit = p->matchMaxLen;
|
||||
p->lenLimit = lenLimit;
|
||||
}
|
||||
p->posLimit = p->pos + limit;
|
||||
}
|
||||
|
||||
void MatchFinder_Init(CMatchFinder *p)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < p->hashSizeSum; i++)
|
||||
p->hash[i] = kEmptyHashValue;
|
||||
p->cyclicBufferPos = 0;
|
||||
p->buffer = p->bufferBase;
|
||||
p->pos = p->streamPos = p->cyclicBufferSize;
|
||||
p->result = SZ_OK;
|
||||
p->streamEndWasReached = 0;
|
||||
MatchFinder_ReadBlock(p);
|
||||
MatchFinder_SetLimits(p);
|
||||
}
|
||||
|
||||
static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
|
||||
{
|
||||
return (p->pos - p->historySize - 1) & kNormalizeMask;
|
||||
}
|
||||
|
||||
void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 value = items[i];
|
||||
if (value <= subValue)
|
||||
value = kEmptyHashValue;
|
||||
else
|
||||
value -= subValue;
|
||||
items[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void MatchFinder_Normalize(CMatchFinder *p)
|
||||
{
|
||||
UInt32 subValue = MatchFinder_GetSubValue(p);
|
||||
MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
|
||||
MatchFinder_ReduceOffsets(p, subValue);
|
||||
}
|
||||
|
||||
static void MatchFinder_CheckLimits(CMatchFinder *p)
|
||||
{
|
||||
if (p->pos == kMaxValForNormalize)
|
||||
MatchFinder_Normalize(p);
|
||||
if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
|
||||
MatchFinder_CheckAndMoveAndRead(p);
|
||||
if (p->cyclicBufferPos == p->cyclicBufferSize)
|
||||
p->cyclicBufferPos = 0;
|
||||
MatchFinder_SetLimits(p);
|
||||
}
|
||||
|
||||
static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
|
||||
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
|
||||
UInt32 *distances, UInt32 maxLen)
|
||||
{
|
||||
son[_cyclicBufferPos] = curMatch;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 delta = pos - curMatch;
|
||||
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
|
||||
return distances;
|
||||
{
|
||||
const Byte *pb = cur - delta;
|
||||
curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
|
||||
if (pb[maxLen] == cur[maxLen] && *pb == *cur)
|
||||
{
|
||||
UInt32 len = 0;
|
||||
while (++len != lenLimit)
|
||||
if (pb[len] != cur[len])
|
||||
break;
|
||||
if (maxLen < len)
|
||||
{
|
||||
*distances++ = maxLen = len;
|
||||
*distances++ = delta - 1;
|
||||
if (len == lenLimit)
|
||||
return distances;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
|
||||
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
|
||||
UInt32 *distances, UInt32 maxLen)
|
||||
{
|
||||
CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
|
||||
CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
|
||||
UInt32 len0 = 0, len1 = 0;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 delta = pos - curMatch;
|
||||
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
|
||||
{
|
||||
*ptr0 = *ptr1 = kEmptyHashValue;
|
||||
return distances;
|
||||
}
|
||||
{
|
||||
CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
|
||||
const Byte *pb = cur - delta;
|
||||
UInt32 len = (len0 < len1 ? len0 : len1);
|
||||
if (pb[len] == cur[len])
|
||||
{
|
||||
if (++len != lenLimit && pb[len] == cur[len])
|
||||
while (++len != lenLimit)
|
||||
if (pb[len] != cur[len])
|
||||
break;
|
||||
if (maxLen < len)
|
||||
{
|
||||
*distances++ = maxLen = len;
|
||||
*distances++ = delta - 1;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
*ptr1 = pair[0];
|
||||
*ptr0 = pair[1];
|
||||
return distances;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pb[len] < cur[len])
|
||||
{
|
||||
*ptr1 = curMatch;
|
||||
ptr1 = pair + 1;
|
||||
curMatch = *ptr1;
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr0 = curMatch;
|
||||
ptr0 = pair;
|
||||
curMatch = *ptr0;
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
|
||||
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
|
||||
{
|
||||
CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
|
||||
CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
|
||||
UInt32 len0 = 0, len1 = 0;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 delta = pos - curMatch;
|
||||
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
|
||||
{
|
||||
*ptr0 = *ptr1 = kEmptyHashValue;
|
||||
return;
|
||||
}
|
||||
{
|
||||
CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
|
||||
const Byte *pb = cur - delta;
|
||||
UInt32 len = (len0 < len1 ? len0 : len1);
|
||||
if (pb[len] == cur[len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
if (pb[len] != cur[len])
|
||||
break;
|
||||
{
|
||||
if (len == lenLimit)
|
||||
{
|
||||
*ptr1 = pair[0];
|
||||
*ptr0 = pair[1];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pb[len] < cur[len])
|
||||
{
|
||||
*ptr1 = curMatch;
|
||||
ptr1 = pair + 1;
|
||||
curMatch = *ptr1;
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr0 = curMatch;
|
||||
ptr0 = pair;
|
||||
curMatch = *ptr0;
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MOVE_POS \
|
||||
++p->cyclicBufferPos; \
|
||||
p->buffer++; \
|
||||
if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
|
||||
|
||||
#define MOVE_POS_RET MOVE_POS return offset;
|
||||
|
||||
static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
|
||||
|
||||
#define GET_MATCHES_HEADER2(minLen, ret_op) \
|
||||
UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
|
||||
lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
|
||||
cur = p->buffer;
|
||||
|
||||
#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
|
||||
#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
|
||||
|
||||
#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
|
||||
|
||||
#define GET_MATCHES_FOOTER(offset, maxLen) \
|
||||
offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
|
||||
distances + offset, maxLen) - distances); MOVE_POS_RET;
|
||||
|
||||
#define SKIP_FOOTER \
|
||||
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
|
||||
|
||||
static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 offset;
|
||||
GET_MATCHES_HEADER(2)
|
||||
HASH2_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
offset = 0;
|
||||
GET_MATCHES_FOOTER(offset, 1)
|
||||
}
|
||||
|
||||
UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 offset;
|
||||
GET_MATCHES_HEADER(3)
|
||||
HASH_ZIP_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
offset = 0;
|
||||
GET_MATCHES_FOOTER(offset, 2)
|
||||
}
|
||||
|
||||
static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 hash2Value, delta2, maxLen, offset;
|
||||
GET_MATCHES_HEADER(3)
|
||||
|
||||
HASH3_CALC;
|
||||
|
||||
delta2 = p->pos - p->hash[hash2Value];
|
||||
curMatch = p->hash[kFix3HashSize + hashValue];
|
||||
|
||||
p->hash[hash2Value] =
|
||||
p->hash[kFix3HashSize + hashValue] = p->pos;
|
||||
|
||||
maxLen = 2;
|
||||
offset = 0;
|
||||
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
|
||||
{
|
||||
for (; maxLen != lenLimit; maxLen++)
|
||||
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
|
||||
break;
|
||||
distances[0] = maxLen;
|
||||
distances[1] = delta2 - 1;
|
||||
offset = 2;
|
||||
if (maxLen == lenLimit)
|
||||
{
|
||||
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
|
||||
MOVE_POS_RET;
|
||||
}
|
||||
}
|
||||
GET_MATCHES_FOOTER(offset, maxLen)
|
||||
}
|
||||
|
||||
static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
|
||||
GET_MATCHES_HEADER(4)
|
||||
|
||||
HASH4_CALC;
|
||||
|
||||
delta2 = p->pos - p->hash[hash2Value];
|
||||
delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
|
||||
curMatch = p->hash[kFix4HashSize + hashValue];
|
||||
|
||||
p->hash[hash2Value] =
|
||||
p->hash[kFix3HashSize + hash3Value] =
|
||||
p->hash[kFix4HashSize + hashValue] = p->pos;
|
||||
|
||||
maxLen = 1;
|
||||
offset = 0;
|
||||
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
|
||||
{
|
||||
distances[0] = maxLen = 2;
|
||||
distances[1] = delta2 - 1;
|
||||
offset = 2;
|
||||
}
|
||||
if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
|
||||
{
|
||||
maxLen = 3;
|
||||
distances[offset + 1] = delta3 - 1;
|
||||
offset += 2;
|
||||
delta2 = delta3;
|
||||
}
|
||||
if (offset != 0)
|
||||
{
|
||||
for (; maxLen != lenLimit; maxLen++)
|
||||
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
|
||||
break;
|
||||
distances[offset - 2] = maxLen;
|
||||
if (maxLen == lenLimit)
|
||||
{
|
||||
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
|
||||
MOVE_POS_RET;
|
||||
}
|
||||
}
|
||||
if (maxLen < 3)
|
||||
maxLen = 3;
|
||||
GET_MATCHES_FOOTER(offset, maxLen)
|
||||
}
|
||||
|
||||
static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
|
||||
GET_MATCHES_HEADER(4)
|
||||
|
||||
HASH4_CALC;
|
||||
|
||||
delta2 = p->pos - p->hash[hash2Value];
|
||||
delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
|
||||
curMatch = p->hash[kFix4HashSize + hashValue];
|
||||
|
||||
p->hash[hash2Value] =
|
||||
p->hash[kFix3HashSize + hash3Value] =
|
||||
p->hash[kFix4HashSize + hashValue] = p->pos;
|
||||
|
||||
maxLen = 1;
|
||||
offset = 0;
|
||||
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
|
||||
{
|
||||
distances[0] = maxLen = 2;
|
||||
distances[1] = delta2 - 1;
|
||||
offset = 2;
|
||||
}
|
||||
if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
|
||||
{
|
||||
maxLen = 3;
|
||||
distances[offset + 1] = delta3 - 1;
|
||||
offset += 2;
|
||||
delta2 = delta3;
|
||||
}
|
||||
if (offset != 0)
|
||||
{
|
||||
for (; maxLen != lenLimit; maxLen++)
|
||||
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
|
||||
break;
|
||||
distances[offset - 2] = maxLen;
|
||||
if (maxLen == lenLimit)
|
||||
{
|
||||
p->son[p->cyclicBufferPos] = curMatch;
|
||||
MOVE_POS_RET;
|
||||
}
|
||||
}
|
||||
if (maxLen < 3)
|
||||
maxLen = 3;
|
||||
offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
|
||||
distances + offset, maxLen) - (distances));
|
||||
MOVE_POS_RET
|
||||
}
|
||||
|
||||
UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 offset;
|
||||
GET_MATCHES_HEADER(3)
|
||||
HASH_ZIP_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
|
||||
distances, 2) - (distances));
|
||||
MOVE_POS_RET
|
||||
}
|
||||
|
||||
static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
SKIP_HEADER(2)
|
||||
HASH2_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
SKIP_FOOTER
|
||||
} while (--num != 0);
|
||||
}
|
||||
|
||||
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
SKIP_HEADER(3)
|
||||
HASH_ZIP_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
SKIP_FOOTER
|
||||
} while (--num != 0);
|
||||
}
|
||||
|
||||
static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 hash2Value;
|
||||
SKIP_HEADER(3)
|
||||
HASH3_CALC;
|
||||
curMatch = p->hash[kFix3HashSize + hashValue];
|
||||
p->hash[hash2Value] =
|
||||
p->hash[kFix3HashSize + hashValue] = p->pos;
|
||||
SKIP_FOOTER
|
||||
} while (--num != 0);
|
||||
}
|
||||
|
||||
static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 hash2Value, hash3Value;
|
||||
SKIP_HEADER(4)
|
||||
HASH4_CALC;
|
||||
curMatch = p->hash[kFix4HashSize + hashValue];
|
||||
p->hash[hash2Value] =
|
||||
p->hash[kFix3HashSize + hash3Value] = p->pos;
|
||||
p->hash[kFix4HashSize + hashValue] = p->pos;
|
||||
SKIP_FOOTER
|
||||
} while (--num != 0);
|
||||
}
|
||||
|
||||
static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 hash2Value, hash3Value;
|
||||
SKIP_HEADER(4)
|
||||
HASH4_CALC;
|
||||
curMatch = p->hash[kFix4HashSize + hashValue];
|
||||
p->hash[hash2Value] =
|
||||
p->hash[kFix3HashSize + hash3Value] =
|
||||
p->hash[kFix4HashSize + hashValue] = p->pos;
|
||||
p->son[p->cyclicBufferPos] = curMatch;
|
||||
MOVE_POS
|
||||
} while (--num != 0);
|
||||
}
|
||||
|
||||
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
SKIP_HEADER(3)
|
||||
HASH_ZIP_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
p->son[p->cyclicBufferPos] = curMatch;
|
||||
MOVE_POS
|
||||
} while (--num != 0);
|
||||
}
|
||||
|
||||
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
|
||||
{
|
||||
vTable->Init = (Mf_Init_Func)MatchFinder_Init;
|
||||
vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
|
||||
vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
|
||||
vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
|
||||
if (!p->btMode)
|
||||
{
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
|
||||
vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
|
||||
}
|
||||
else if (p->numHashBytes == 2)
|
||||
{
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
|
||||
vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
|
||||
}
|
||||
else if (p->numHashBytes == 3)
|
||||
{
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
|
||||
vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
|
||||
}
|
||||
else
|
||||
{
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
|
||||
vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/* LzFind.h -- Match finder for LZ algorithms
|
||||
2009-04-22 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZ_FIND_H
|
||||
#define __LZ_FIND_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef UInt32 CLzRef;
|
||||
|
||||
typedef struct _CMatchFinder
|
||||
{
|
||||
Byte *buffer;
|
||||
UInt32 pos;
|
||||
UInt32 posLimit;
|
||||
UInt32 streamPos;
|
||||
UInt32 lenLimit;
|
||||
|
||||
UInt32 cyclicBufferPos;
|
||||
UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
|
||||
|
||||
UInt32 matchMaxLen;
|
||||
CLzRef *hash;
|
||||
CLzRef *son;
|
||||
UInt32 hashMask;
|
||||
UInt32 cutValue;
|
||||
|
||||
Byte *bufferBase;
|
||||
ISeqInStream *stream;
|
||||
int streamEndWasReached;
|
||||
|
||||
UInt32 blockSize;
|
||||
UInt32 keepSizeBefore;
|
||||
UInt32 keepSizeAfter;
|
||||
|
||||
UInt32 numHashBytes;
|
||||
int directInput;
|
||||
size_t directInputRem;
|
||||
int btMode;
|
||||
int bigHash;
|
||||
UInt32 historySize;
|
||||
UInt32 fixedHashSize;
|
||||
UInt32 hashSizeSum;
|
||||
UInt32 numSons;
|
||||
SRes result;
|
||||
UInt32 crc[256];
|
||||
} CMatchFinder;
|
||||
|
||||
#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
|
||||
#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
|
||||
|
||||
#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
|
||||
|
||||
int MatchFinder_NeedMove(CMatchFinder *p);
|
||||
Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
|
||||
void MatchFinder_MoveBlock(CMatchFinder *p);
|
||||
void MatchFinder_ReadIfRequired(CMatchFinder *p);
|
||||
|
||||
void MatchFinder_Construct(CMatchFinder *p);
|
||||
|
||||
/* Conditions:
|
||||
historySize <= 3 GB
|
||||
keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
|
||||
*/
|
||||
int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
|
||||
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
|
||||
ISzAlloc *alloc);
|
||||
void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
|
||||
void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
|
||||
void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
|
||||
|
||||
UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
|
||||
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
|
||||
UInt32 *distances, UInt32 maxLen);
|
||||
|
||||
/*
|
||||
Conditions:
|
||||
Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
|
||||
Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
|
||||
*/
|
||||
|
||||
typedef void (*Mf_Init_Func)(void *object);
|
||||
typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
|
||||
typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
|
||||
typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
|
||||
typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
|
||||
typedef void (*Mf_Skip_Func)(void *object, UInt32);
|
||||
|
||||
typedef struct _IMatchFinder
|
||||
{
|
||||
Mf_Init_Func Init;
|
||||
Mf_GetIndexByte_Func GetIndexByte;
|
||||
Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
|
||||
Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
|
||||
Mf_GetMatches_Func GetMatches;
|
||||
Mf_Skip_Func Skip;
|
||||
} IMatchFinder;
|
||||
|
||||
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
|
||||
|
||||
void MatchFinder_Init(CMatchFinder *p);
|
||||
UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
|
||||
UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
|
||||
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
|
||||
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,54 +0,0 @@
|
|||
/* LzHash.h -- HASH functions for LZ algorithms
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZ_HASH_H
|
||||
#define __LZ_HASH_H
|
||||
|
||||
#define kHash2Size (1 << 10)
|
||||
#define kHash3Size (1 << 16)
|
||||
#define kHash4Size (1 << 20)
|
||||
|
||||
#define kFix3HashSize (kHash2Size)
|
||||
#define kFix4HashSize (kHash2Size + kHash3Size)
|
||||
#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
|
||||
|
||||
#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
|
||||
|
||||
#define HASH3_CALC { \
|
||||
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
|
||||
hash2Value = temp & (kHash2Size - 1); \
|
||||
hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
|
||||
|
||||
#define HASH4_CALC { \
|
||||
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
|
||||
hash2Value = temp & (kHash2Size - 1); \
|
||||
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
|
||||
hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
|
||||
|
||||
#define HASH5_CALC { \
|
||||
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
|
||||
hash2Value = temp & (kHash2Size - 1); \
|
||||
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
|
||||
hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
|
||||
hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
|
||||
hash4Value &= (kHash4Size - 1); }
|
||||
|
||||
/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
|
||||
#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
|
||||
|
||||
|
||||
#define MT_HASH2_CALC \
|
||||
hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
|
||||
|
||||
#define MT_HASH3_CALC { \
|
||||
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
|
||||
hash2Value = temp & (kHash2Size - 1); \
|
||||
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
|
||||
|
||||
#define MT_HASH4_CALC { \
|
||||
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
|
||||
hash2Value = temp & (kHash2Size - 1); \
|
||||
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
|
||||
hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
|
||||
|
||||
#endif
|
|
@ -1,987 +0,0 @@
|
|||
/* LzmaDec.c -- LZMA Decoder
|
||||
2009-09-20 : Igor Pavlov : Public domain*/
|
||||
|
||||
#include "LzmaDec.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define kNumTopBits 24
|
||||
#define kTopValue ((UInt32)1 << kNumTopBits)
|
||||
|
||||
#define kNumBitModelTotalBits 11
|
||||
#define kBitModelTotal (1 << kNumBitModelTotalBits)
|
||||
#define kNumMoveBits 5
|
||||
|
||||
#define RC_INIT_SIZE 5
|
||||
|
||||
#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
|
||||
|
||||
#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
|
||||
#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
|
||||
#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
|
||||
#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
|
||||
{ UPDATE_0(p); i = (i + i); A0; } else \
|
||||
{ UPDATE_1(p); i = (i + i) + 1; A1; }
|
||||
#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
|
||||
|
||||
#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
|
||||
#define TREE_DECODE(probs, limit, i) \
|
||||
{ i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
|
||||
|
||||
/* #define _LZMA_SIZE_OPT */
|
||||
|
||||
#ifdef _LZMA_SIZE_OPT
|
||||
#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
|
||||
#else
|
||||
#define TREE_6_DECODE(probs, i) \
|
||||
{ i = 1; \
|
||||
TREE_GET_BIT(probs, i); \
|
||||
TREE_GET_BIT(probs, i); \
|
||||
TREE_GET_BIT(probs, i); \
|
||||
TREE_GET_BIT(probs, i); \
|
||||
TREE_GET_BIT(probs, i); \
|
||||
TREE_GET_BIT(probs, i); \
|
||||
i -= 0x40; }
|
||||
#endif
|
||||
|
||||
#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
|
||||
|
||||
#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
|
||||
#define UPDATE_0_CHECK range = bound;
|
||||
#define UPDATE_1_CHECK range -= bound; code -= bound;
|
||||
#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
|
||||
{ UPDATE_0_CHECK; i = (i + i); A0; } else \
|
||||
{ UPDATE_1_CHECK; i = (i + i) + 1; A1; }
|
||||
#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
|
||||
#define TREE_DECODE_CHECK(probs, limit, i) \
|
||||
{ i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
|
||||
|
||||
#define kNumPosBitsMax 4
|
||||
#define kNumPosStatesMax (1 << kNumPosBitsMax)
|
||||
|
||||
#define kLenNumLowBits 3
|
||||
#define kLenNumLowSymbols (1 << kLenNumLowBits)
|
||||
#define kLenNumMidBits 3
|
||||
#define kLenNumMidSymbols (1 << kLenNumMidBits)
|
||||
#define kLenNumHighBits 8
|
||||
#define kLenNumHighSymbols (1 << kLenNumHighBits)
|
||||
|
||||
#define LenChoice 0
|
||||
#define LenChoice2 (LenChoice + 1)
|
||||
#define LenLow (LenChoice2 + 1)
|
||||
#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
|
||||
#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
|
||||
#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
|
||||
|
||||
#define kNumStates 12
|
||||
#define kNumLitStates 7
|
||||
|
||||
#define kStartPosModelIndex 4
|
||||
#define kEndPosModelIndex 14
|
||||
#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
|
||||
|
||||
#define kNumPosSlotBits 6
|
||||
#define kNumLenToPosStates 4
|
||||
|
||||
#define kNumAlignBits 4
|
||||
#define kAlignTableSize (1 << kNumAlignBits)
|
||||
|
||||
#define kMatchMinLen 2
|
||||
#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
|
||||
|
||||
#define IsMatch 0
|
||||
#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
|
||||
#define IsRepG0 (IsRep + kNumStates)
|
||||
#define IsRepG1 (IsRepG0 + kNumStates)
|
||||
#define IsRepG2 (IsRepG1 + kNumStates)
|
||||
#define IsRep0Long (IsRepG2 + kNumStates)
|
||||
#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
|
||||
#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
|
||||
#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
|
||||
#define LenCoder (Align + kAlignTableSize)
|
||||
#define RepLenCoder (LenCoder + kNumLenProbs)
|
||||
#define Literal (RepLenCoder + kNumLenProbs)
|
||||
|
||||
#define LZMA_BASE_SIZE 1846
|
||||
#define LZMA_LIT_SIZE 768
|
||||
|
||||
#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
|
||||
|
||||
#if Literal != LZMA_BASE_SIZE
|
||||
StopCompilingDueBUG
|
||||
#endif
|
||||
|
||||
#define LZMA_DIC_MIN (1 << 12)
|
||||
|
||||
/* First LZMA-symbol is always decoded.
|
||||
And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is with last normalization
|
||||
Out:
|
||||
Result:
|
||||
SZ_OK - OK
|
||||
SZ_ERROR_DATA - Error
|
||||
p->remainLen:
|
||||
< kMatchSpecLenStart : normal remain
|
||||
= kMatchSpecLenStart : finished
|
||||
= kMatchSpecLenStart + 1 : Flush marker
|
||||
= kMatchSpecLenStart + 2 : State Init Marker
|
||||
*/
|
||||
|
||||
static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
|
||||
{
|
||||
CLzmaProb *probs = p->probs;
|
||||
|
||||
unsigned state = p->state;
|
||||
UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
|
||||
unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
|
||||
unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
|
||||
unsigned lc = p->prop.lc;
|
||||
|
||||
Byte *dic = p->dic;
|
||||
SizeT dicBufSize = p->dicBufSize;
|
||||
SizeT dicPos = p->dicPos;
|
||||
|
||||
UInt32 processedPos = p->processedPos;
|
||||
UInt32 checkDicSize = p->checkDicSize;
|
||||
unsigned len = 0;
|
||||
|
||||
const Byte *buf = p->buf;
|
||||
UInt32 range = p->range;
|
||||
UInt32 code = p->code;
|
||||
|
||||
do
|
||||
{
|
||||
CLzmaProb *prob;
|
||||
UInt32 bound;
|
||||
unsigned ttt;
|
||||
unsigned posState = processedPos & pbMask;
|
||||
|
||||
prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
|
||||
IF_BIT_0(prob)
|
||||
{
|
||||
unsigned symbol;
|
||||
UPDATE_0(prob);
|
||||
prob = probs + Literal;
|
||||
if (checkDicSize != 0 || processedPos != 0)
|
||||
prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
|
||||
(dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
|
||||
|
||||
if (state < kNumLitStates)
|
||||
{
|
||||
state -= (state < 4) ? state : 3;
|
||||
symbol = 1;
|
||||
do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
|
||||
unsigned offs = 0x100;
|
||||
state -= (state < 10) ? 3 : 6;
|
||||
symbol = 1;
|
||||
do
|
||||
{
|
||||
unsigned bit;
|
||||
CLzmaProb *probLit;
|
||||
matchByte <<= 1;
|
||||
bit = (matchByte & offs);
|
||||
probLit = prob + offs + bit + symbol;
|
||||
GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
|
||||
} while (symbol < 0x100);
|
||||
}
|
||||
dic[dicPos++] = (Byte)symbol;
|
||||
processedPos++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1(prob);
|
||||
prob = probs + IsRep + state;
|
||||
IF_BIT_0(prob)
|
||||
{
|
||||
UPDATE_0(prob);
|
||||
state += kNumStates;
|
||||
prob = probs + LenCoder;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1(prob);
|
||||
if (checkDicSize == 0 && processedPos == 0)
|
||||
return SZ_ERROR_DATA;
|
||||
prob = probs + IsRepG0 + state;
|
||||
IF_BIT_0(prob)
|
||||
{
|
||||
UPDATE_0(prob);
|
||||
prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
|
||||
IF_BIT_0(prob)
|
||||
{
|
||||
UPDATE_0(prob);
|
||||
dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
|
||||
dicPos++;
|
||||
processedPos++;
|
||||
state = state < kNumLitStates ? 9 : 11;
|
||||
continue;
|
||||
}
|
||||
UPDATE_1(prob);
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 distance;
|
||||
UPDATE_1(prob);
|
||||
prob = probs + IsRepG1 + state;
|
||||
IF_BIT_0(prob)
|
||||
{
|
||||
UPDATE_0(prob);
|
||||
distance = rep1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1(prob);
|
||||
prob = probs + IsRepG2 + state;
|
||||
IF_BIT_0(prob)
|
||||
{
|
||||
UPDATE_0(prob);
|
||||
distance = rep2;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1(prob);
|
||||
distance = rep3;
|
||||
rep3 = rep2;
|
||||
}
|
||||
rep2 = rep1;
|
||||
}
|
||||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
state = state < kNumLitStates ? 8 : 11;
|
||||
prob = probs + RepLenCoder;
|
||||
}
|
||||
{
|
||||
unsigned limit, offset;
|
||||
CLzmaProb *probLen = prob + LenChoice;
|
||||
IF_BIT_0(probLen)
|
||||
{
|
||||
UPDATE_0(probLen);
|
||||
probLen = prob + LenLow + (posState << kLenNumLowBits);
|
||||
offset = 0;
|
||||
limit = (1 << kLenNumLowBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1(probLen);
|
||||
probLen = prob + LenChoice2;
|
||||
IF_BIT_0(probLen)
|
||||
{
|
||||
UPDATE_0(probLen);
|
||||
probLen = prob + LenMid + (posState << kLenNumMidBits);
|
||||
offset = kLenNumLowSymbols;
|
||||
limit = (1 << kLenNumMidBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1(probLen);
|
||||
probLen = prob + LenHigh;
|
||||
offset = kLenNumLowSymbols + kLenNumMidSymbols;
|
||||
limit = (1 << kLenNumHighBits);
|
||||
}
|
||||
}
|
||||
TREE_DECODE(probLen, limit, len);
|
||||
len += offset;
|
||||
}
|
||||
|
||||
if (state >= kNumStates)
|
||||
{
|
||||
UInt32 distance;
|
||||
prob = probs + PosSlot +
|
||||
((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
|
||||
TREE_6_DECODE(prob, distance);
|
||||
if (distance >= kStartPosModelIndex)
|
||||
{
|
||||
unsigned posSlot = (unsigned)distance;
|
||||
int numDirectBits = (int)(((distance >> 1) - 1));
|
||||
distance = (2 | (distance & 1));
|
||||
if (posSlot < kEndPosModelIndex)
|
||||
{
|
||||
distance <<= numDirectBits;
|
||||
prob = probs + SpecPos + distance - posSlot - 1;
|
||||
{
|
||||
UInt32 mask = 1;
|
||||
unsigned i = 1;
|
||||
do
|
||||
{
|
||||
GET_BIT2(prob + i, i, ;, distance |= mask);
|
||||
mask <<= 1;
|
||||
} while (--numDirectBits != 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
numDirectBits -= kNumAlignBits;
|
||||
do
|
||||
{
|
||||
NORMALIZE
|
||||
range >>= 1;
|
||||
|
||||
{
|
||||
UInt32 t;
|
||||
code -= range;
|
||||
t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
|
||||
distance = (distance << 1) + (t + 1);
|
||||
code += range & t;
|
||||
}
|
||||
/*
|
||||
distance <<= 1;
|
||||
if (code >= range)
|
||||
{
|
||||
code -= range;
|
||||
distance |= 1;
|
||||
}
|
||||
*/
|
||||
} while (--numDirectBits != 0);
|
||||
prob = probs + Align;
|
||||
distance <<= kNumAlignBits;
|
||||
{
|
||||
unsigned i = 1;
|
||||
GET_BIT2(prob + i, i, ;, distance |= 1);
|
||||
GET_BIT2(prob + i, i, ;, distance |= 2);
|
||||
GET_BIT2(prob + i, i, ;, distance |= 4);
|
||||
GET_BIT2(prob + i, i, ;, distance |= 8);
|
||||
}
|
||||
if (distance == (UInt32)0xFFFFFFFF)
|
||||
{
|
||||
len += kMatchSpecLenStart;
|
||||
state -= kNumStates;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rep3 = rep2;
|
||||
rep2 = rep1;
|
||||
rep1 = rep0;
|
||||
rep0 = distance + 1;
|
||||
if (checkDicSize == 0)
|
||||
{
|
||||
if (distance >= processedPos)
|
||||
return SZ_ERROR_DATA;
|
||||
}
|
||||
else if (distance >= checkDicSize)
|
||||
return SZ_ERROR_DATA;
|
||||
state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
|
||||
}
|
||||
|
||||
len += kMatchMinLen;
|
||||
|
||||
if (limit == dicPos)
|
||||
return SZ_ERROR_DATA;
|
||||
{
|
||||
SizeT rem = limit - dicPos;
|
||||
unsigned curLen = ((rem < len) ? (unsigned)rem : len);
|
||||
SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
|
||||
|
||||
processedPos += curLen;
|
||||
|
||||
len -= curLen;
|
||||
if (pos + curLen <= dicBufSize)
|
||||
{
|
||||
Byte *dest = dic + dicPos;
|
||||
ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
|
||||
const Byte *lim = dest + curLen;
|
||||
dicPos += curLen;
|
||||
do
|
||||
*(dest) = (Byte)*(dest + src);
|
||||
while (++dest != lim);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
dic[dicPos++] = dic[pos];
|
||||
if (++pos == dicBufSize)
|
||||
pos = 0;
|
||||
} while (--curLen != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (dicPos < limit && buf < bufLimit);
|
||||
NORMALIZE;
|
||||
p->buf = buf;
|
||||
p->range = range;
|
||||
p->code = code;
|
||||
p->remainLen = len;
|
||||
p->dicPos = dicPos;
|
||||
p->processedPos = processedPos;
|
||||
p->reps[0] = rep0;
|
||||
p->reps[1] = rep1;
|
||||
p->reps[2] = rep2;
|
||||
p->reps[3] = rep3;
|
||||
p->state = state;
|
||||
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
|
||||
{
|
||||
if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
|
||||
{
|
||||
Byte *dic = p->dic;
|
||||
SizeT dicPos = p->dicPos;
|
||||
SizeT dicBufSize = p->dicBufSize;
|
||||
unsigned len = p->remainLen;
|
||||
UInt32 rep0 = p->reps[0];
|
||||
if (limit - dicPos < len)
|
||||
len = (unsigned)(limit - dicPos);
|
||||
|
||||
if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
|
||||
p->checkDicSize = p->prop.dicSize;
|
||||
|
||||
p->processedPos += len;
|
||||
p->remainLen -= len;
|
||||
while (len-- != 0)
|
||||
{
|
||||
dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
|
||||
dicPos++;
|
||||
}
|
||||
p->dicPos = dicPos;
|
||||
}
|
||||
}
|
||||
|
||||
static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
|
||||
{
|
||||
do
|
||||
{
|
||||
SizeT limit2 = limit;
|
||||
if (p->checkDicSize == 0)
|
||||
{
|
||||
UInt32 rem = p->prop.dicSize - p->processedPos;
|
||||
if (limit - p->dicPos > rem)
|
||||
limit2 = p->dicPos + rem;
|
||||
}
|
||||
RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
|
||||
if (p->processedPos >= p->prop.dicSize)
|
||||
p->checkDicSize = p->prop.dicSize;
|
||||
LzmaDec_WriteRem(p, limit);
|
||||
} while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
|
||||
|
||||
if (p->remainLen > kMatchSpecLenStart)
|
||||
{
|
||||
p->remainLen = kMatchSpecLenStart;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DUMMY_ERROR, /* unexpected end of input stream */
|
||||
DUMMY_LIT,
|
||||
DUMMY_MATCH,
|
||||
DUMMY_REP
|
||||
} ELzmaDummy;
|
||||
|
||||
static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
|
||||
{
|
||||
UInt32 range = p->range;
|
||||
UInt32 code = p->code;
|
||||
const Byte *bufLimit = buf + inSize;
|
||||
CLzmaProb *probs = p->probs;
|
||||
unsigned state = p->state;
|
||||
ELzmaDummy res;
|
||||
|
||||
{
|
||||
CLzmaProb *prob;
|
||||
UInt32 bound;
|
||||
unsigned ttt;
|
||||
unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
|
||||
|
||||
prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
|
||||
IF_BIT_0_CHECK(prob)
|
||||
{
|
||||
UPDATE_0_CHECK
|
||||
|
||||
/* if (bufLimit - buf >= 7) return DUMMY_LIT; */
|
||||
|
||||
prob = probs + Literal;
|
||||
if (p->checkDicSize != 0 || p->processedPos != 0)
|
||||
prob += (LZMA_LIT_SIZE *
|
||||
((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
|
||||
(p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
|
||||
|
||||
if (state < kNumLitStates)
|
||||
{
|
||||
unsigned symbol = 1;
|
||||
do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
|
||||
((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
|
||||
unsigned offs = 0x100;
|
||||
unsigned symbol = 1;
|
||||
do
|
||||
{
|
||||
unsigned bit;
|
||||
CLzmaProb *probLit;
|
||||
matchByte <<= 1;
|
||||
bit = (matchByte & offs);
|
||||
probLit = prob + offs + bit + symbol;
|
||||
GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
|
||||
} while (symbol < 0x100);
|
||||
}
|
||||
res = DUMMY_LIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned len;
|
||||
UPDATE_1_CHECK;
|
||||
|
||||
prob = probs + IsRep + state;
|
||||
IF_BIT_0_CHECK(prob)
|
||||
{
|
||||
UPDATE_0_CHECK;
|
||||
state = 0;
|
||||
prob = probs + LenCoder;
|
||||
res = DUMMY_MATCH;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1_CHECK;
|
||||
res = DUMMY_REP;
|
||||
prob = probs + IsRepG0 + state;
|
||||
IF_BIT_0_CHECK(prob)
|
||||
{
|
||||
UPDATE_0_CHECK;
|
||||
prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
|
||||
IF_BIT_0_CHECK(prob)
|
||||
{
|
||||
UPDATE_0_CHECK;
|
||||
NORMALIZE_CHECK;
|
||||
return DUMMY_REP;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1_CHECK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1_CHECK;
|
||||
prob = probs + IsRepG1 + state;
|
||||
IF_BIT_0_CHECK(prob)
|
||||
{
|
||||
UPDATE_0_CHECK;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1_CHECK;
|
||||
prob = probs + IsRepG2 + state;
|
||||
IF_BIT_0_CHECK(prob)
|
||||
{
|
||||
UPDATE_0_CHECK;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1_CHECK;
|
||||
}
|
||||
}
|
||||
}
|
||||
state = kNumStates;
|
||||
prob = probs + RepLenCoder;
|
||||
}
|
||||
{
|
||||
unsigned limit, offset;
|
||||
CLzmaProb *probLen = prob + LenChoice;
|
||||
IF_BIT_0_CHECK(probLen)
|
||||
{
|
||||
UPDATE_0_CHECK;
|
||||
probLen = prob + LenLow + (posState << kLenNumLowBits);
|
||||
offset = 0;
|
||||
limit = 1 << kLenNumLowBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1_CHECK;
|
||||
probLen = prob + LenChoice2;
|
||||
IF_BIT_0_CHECK(probLen)
|
||||
{
|
||||
UPDATE_0_CHECK;
|
||||
probLen = prob + LenMid + (posState << kLenNumMidBits);
|
||||
offset = kLenNumLowSymbols;
|
||||
limit = 1 << kLenNumMidBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPDATE_1_CHECK;
|
||||
probLen = prob + LenHigh;
|
||||
offset = kLenNumLowSymbols + kLenNumMidSymbols;
|
||||
limit = 1 << kLenNumHighBits;
|
||||
}
|
||||
}
|
||||
TREE_DECODE_CHECK(probLen, limit, len);
|
||||
len += offset;
|
||||
}
|
||||
|
||||
if (state < 4)
|
||||
{
|
||||
unsigned posSlot;
|
||||
prob = probs + PosSlot +
|
||||
((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
|
||||
kNumPosSlotBits);
|
||||
TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
|
||||
if (posSlot >= kStartPosModelIndex)
|
||||
{
|
||||
int numDirectBits = ((posSlot >> 1) - 1);
|
||||
|
||||
/* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
|
||||
|
||||
if (posSlot < kEndPosModelIndex)
|
||||
{
|
||||
prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
numDirectBits -= kNumAlignBits;
|
||||
do
|
||||
{
|
||||
NORMALIZE_CHECK
|
||||
range >>= 1;
|
||||
code -= range & (((code - range) >> 31) - 1);
|
||||
/* if (code >= range) code -= range; */
|
||||
} while (--numDirectBits != 0);
|
||||
prob = probs + Align;
|
||||
numDirectBits = kNumAlignBits;
|
||||
}
|
||||
{
|
||||
unsigned i = 1;
|
||||
do
|
||||
{
|
||||
GET_BIT_CHECK(prob + i, i);
|
||||
} while (--numDirectBits != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NORMALIZE_CHECK;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
|
||||
{
|
||||
p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
|
||||
p->range = 0xFFFFFFFF;
|
||||
p->needFlush = 0;
|
||||
}
|
||||
|
||||
void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
|
||||
{
|
||||
p->needFlush = 1;
|
||||
p->remainLen = 0;
|
||||
p->tempBufSize = 0;
|
||||
|
||||
if (initDic)
|
||||
{
|
||||
p->processedPos = 0;
|
||||
p->checkDicSize = 0;
|
||||
p->needInitState = 1;
|
||||
}
|
||||
if (initState)
|
||||
p->needInitState = 1;
|
||||
}
|
||||
|
||||
void LzmaDec_Init(CLzmaDec *p)
|
||||
{
|
||||
p->dicPos = 0;
|
||||
LzmaDec_InitDicAndState(p, True, True);
|
||||
}
|
||||
|
||||
static void LzmaDec_InitStateReal(CLzmaDec *p)
|
||||
{
|
||||
UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
|
||||
UInt32 i;
|
||||
CLzmaProb *probs = p->probs;
|
||||
for (i = 0; i < numProbs; i++)
|
||||
probs[i] = kBitModelTotal >> 1;
|
||||
p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
|
||||
p->state = 0;
|
||||
p->needInitState = 0;
|
||||
}
|
||||
|
||||
SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
|
||||
ELzmaFinishMode finishMode, ELzmaStatus *status)
|
||||
{
|
||||
SizeT inSize = *srcLen;
|
||||
(*srcLen) = 0;
|
||||
LzmaDec_WriteRem(p, dicLimit);
|
||||
|
||||
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||
|
||||
while (p->remainLen != kMatchSpecLenStart)
|
||||
{
|
||||
int checkEndMarkNow;
|
||||
|
||||
if (p->needFlush != 0)
|
||||
{
|
||||
for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
|
||||
p->tempBuf[p->tempBufSize++] = *src++;
|
||||
if (p->tempBufSize < RC_INIT_SIZE)
|
||||
{
|
||||
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (p->tempBuf[0] != 0)
|
||||
return SZ_ERROR_DATA;
|
||||
|
||||
LzmaDec_InitRc(p, p->tempBuf);
|
||||
p->tempBufSize = 0;
|
||||
}
|
||||
|
||||
checkEndMarkNow = 0;
|
||||
if (p->dicPos >= dicLimit)
|
||||
{
|
||||
if (p->remainLen == 0 && p->code == 0)
|
||||
{
|
||||
*status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (finishMode == LZMA_FINISH_ANY)
|
||||
{
|
||||
*status = LZMA_STATUS_NOT_FINISHED;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (p->remainLen != 0)
|
||||
{
|
||||
*status = LZMA_STATUS_NOT_FINISHED;
|
||||
return SZ_ERROR_DATA;
|
||||
}
|
||||
checkEndMarkNow = 1;
|
||||
}
|
||||
|
||||
if (p->needInitState)
|
||||
LzmaDec_InitStateReal(p);
|
||||
|
||||
if (p->tempBufSize == 0)
|
||||
{
|
||||
SizeT processed;
|
||||
const Byte *bufLimit;
|
||||
if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
|
||||
{
|
||||
int dummyRes = LzmaDec_TryDummy(p, src, inSize);
|
||||
if (dummyRes == DUMMY_ERROR)
|
||||
{
|
||||
memcpy(p->tempBuf, src, inSize);
|
||||
p->tempBufSize = (unsigned)inSize;
|
||||
(*srcLen) += inSize;
|
||||
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
|
||||
{
|
||||
*status = LZMA_STATUS_NOT_FINISHED;
|
||||
return SZ_ERROR_DATA;
|
||||
}
|
||||
bufLimit = src;
|
||||
}
|
||||
else
|
||||
bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
|
||||
p->buf = src;
|
||||
if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
|
||||
return SZ_ERROR_DATA;
|
||||
processed = (SizeT)(p->buf - src);
|
||||
(*srcLen) += processed;
|
||||
src += processed;
|
||||
inSize -= processed;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned rem = p->tempBufSize, lookAhead = 0;
|
||||
while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
|
||||
p->tempBuf[rem++] = src[lookAhead++];
|
||||
p->tempBufSize = rem;
|
||||
if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
|
||||
{
|
||||
int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
|
||||
if (dummyRes == DUMMY_ERROR)
|
||||
{
|
||||
(*srcLen) += lookAhead;
|
||||
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
|
||||
{
|
||||
*status = LZMA_STATUS_NOT_FINISHED;
|
||||
return SZ_ERROR_DATA;
|
||||
}
|
||||
}
|
||||
p->buf = p->tempBuf;
|
||||
if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
|
||||
return SZ_ERROR_DATA;
|
||||
lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
|
||||
(*srcLen) += lookAhead;
|
||||
src += lookAhead;
|
||||
inSize -= lookAhead;
|
||||
p->tempBufSize = 0;
|
||||
}
|
||||
}
|
||||
if (p->code == 0)
|
||||
*status = LZMA_STATUS_FINISHED_WITH_MARK;
|
||||
return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
|
||||
}
|
||||
|
||||
SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
|
||||
{
|
||||
SizeT outSize = *destLen;
|
||||
SizeT inSize = *srcLen;
|
||||
*srcLen = *destLen = 0;
|
||||
for (;;)
|
||||
{
|
||||
SizeT inSizeCur = inSize, outSizeCur, dicPos;
|
||||
ELzmaFinishMode curFinishMode;
|
||||
SRes res;
|
||||
if (p->dicPos == p->dicBufSize)
|
||||
p->dicPos = 0;
|
||||
dicPos = p->dicPos;
|
||||
if (outSize > p->dicBufSize - dicPos)
|
||||
{
|
||||
outSizeCur = p->dicBufSize;
|
||||
curFinishMode = LZMA_FINISH_ANY;
|
||||
}
|
||||
else
|
||||
{
|
||||
outSizeCur = dicPos + outSize;
|
||||
curFinishMode = finishMode;
|
||||
}
|
||||
|
||||
res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
|
||||
src += inSizeCur;
|
||||
inSize -= inSizeCur;
|
||||
*srcLen += inSizeCur;
|
||||
outSizeCur = p->dicPos - dicPos;
|
||||
memcpy(dest, p->dic + dicPos, outSizeCur);
|
||||
dest += outSizeCur;
|
||||
outSize -= outSizeCur;
|
||||
*destLen += outSizeCur;
|
||||
if (res != 0)
|
||||
return res;
|
||||
if (outSizeCur == 0 || outSize == 0)
|
||||
return SZ_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, p->probs);
|
||||
p->probs = 0;
|
||||
}
|
||||
|
||||
static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, p->dic);
|
||||
p->dic = 0;
|
||||
}
|
||||
|
||||
void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
|
||||
{
|
||||
LzmaDec_FreeProbs(p, alloc);
|
||||
LzmaDec_FreeDict(p, alloc);
|
||||
}
|
||||
|
||||
SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
|
||||
{
|
||||
UInt32 dicSize;
|
||||
Byte d;
|
||||
|
||||
if (size < LZMA_PROPS_SIZE)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
else
|
||||
dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
|
||||
|
||||
if (dicSize < LZMA_DIC_MIN)
|
||||
dicSize = LZMA_DIC_MIN;
|
||||
p->dicSize = dicSize;
|
||||
|
||||
d = data[0];
|
||||
if (d >= (9 * 5 * 5))
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
|
||||
p->lc = d % 9;
|
||||
d /= 9;
|
||||
p->pb = d / 5;
|
||||
p->lp = d % 5;
|
||||
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
|
||||
{
|
||||
UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
|
||||
if (p->probs == 0 || numProbs != p->numProbs)
|
||||
{
|
||||
LzmaDec_FreeProbs(p, alloc);
|
||||
p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
|
||||
p->numProbs = numProbs;
|
||||
if (p->probs == 0)
|
||||
return SZ_ERROR_MEM;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
|
||||
{
|
||||
CLzmaProps propNew;
|
||||
RINOK(LzmaProps_Decode(&propNew, props, propsSize));
|
||||
RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
|
||||
p->prop = propNew;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
|
||||
{
|
||||
CLzmaProps propNew;
|
||||
SizeT dicBufSize;
|
||||
RINOK(LzmaProps_Decode(&propNew, props, propsSize));
|
||||
RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
|
||||
dicBufSize = propNew.dicSize;
|
||||
if (p->dic == 0 || dicBufSize != p->dicBufSize)
|
||||
{
|
||||
LzmaDec_FreeDict(p, alloc);
|
||||
p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
|
||||
if (p->dic == 0)
|
||||
{
|
||||
LzmaDec_FreeProbs(p, alloc);
|
||||
return SZ_ERROR_MEM;
|
||||
}
|
||||
}
|
||||
p->dicBufSize = dicBufSize;
|
||||
p->prop = propNew;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
|
||||
ELzmaStatus *status, ISzAlloc *alloc)
|
||||
{
|
||||
CLzmaDec p;
|
||||
SRes res;
|
||||
SizeT inSize = *srcLen;
|
||||
SizeT outSize = *destLen;
|
||||
*srcLen = *destLen = 0;
|
||||
if (inSize < RC_INIT_SIZE)
|
||||
return SZ_ERROR_INPUT_EOF;
|
||||
|
||||
LzmaDec_Construct(&p);
|
||||
res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
|
||||
if (res != 0)
|
||||
return res;
|
||||
p.dic = dest;
|
||||
p.dicBufSize = outSize;
|
||||
|
||||
LzmaDec_Init(&p);
|
||||
|
||||
*srcLen = inSize;
|
||||
res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
|
||||
|
||||
if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||
res = SZ_ERROR_INPUT_EOF;
|
||||
|
||||
(*destLen) = p.dicPos;
|
||||
LzmaDec_FreeProbs(&p, alloc);
|
||||
return res;
|
||||
}
|
2248
LZMA/SDK/C/LzmaEnc.c
|
@ -1,80 +0,0 @@
|
|||
/* LzmaEnc.h -- LZMA Encoder
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZMA_ENC_H
|
||||
#define __LZMA_ENC_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LZMA_PROPS_SIZE 5
|
||||
|
||||
typedef struct _CLzmaEncProps
|
||||
{
|
||||
int level; /* 0 <= level <= 9 */
|
||||
UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
|
||||
(1 << 12) <= dictSize <= (1 << 30) for 64-bit version
|
||||
default = (1 << 24) */
|
||||
int lc; /* 0 <= lc <= 8, default = 3 */
|
||||
int lp; /* 0 <= lp <= 4, default = 0 */
|
||||
int pb; /* 0 <= pb <= 4, default = 2 */
|
||||
int algo; /* 0 - fast, 1 - normal, default = 1 */
|
||||
int fb; /* 5 <= fb <= 273, default = 32 */
|
||||
int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
|
||||
int numHashBytes; /* 2, 3 or 4, default = 4 */
|
||||
UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */
|
||||
unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
|
||||
int numThreads; /* 1 or 2, default = 2 */
|
||||
} CLzmaEncProps;
|
||||
|
||||
void LzmaEncProps_Init(CLzmaEncProps *p);
|
||||
void LzmaEncProps_Normalize(CLzmaEncProps *p);
|
||||
UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
|
||||
|
||||
|
||||
/* ---------- CLzmaEncHandle Interface ---------- */
|
||||
|
||||
/* LzmaEnc_* functions can return the following exit codes:
|
||||
Returns:
|
||||
SZ_OK - OK
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_PARAM - Incorrect paramater in props
|
||||
SZ_ERROR_WRITE - Write callback error.
|
||||
SZ_ERROR_PROGRESS - some break from progress callback
|
||||
SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
|
||||
*/
|
||||
|
||||
typedef void * CLzmaEncHandle;
|
||||
|
||||
CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
|
||||
void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
|
||||
SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
|
||||
SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
|
||||
SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
|
||||
ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
|
||||
SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
|
||||
int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
|
||||
|
||||
/* ---------- One Call Interface ---------- */
|
||||
|
||||
/* LzmaEncode
|
||||
Return code:
|
||||
SZ_OK - OK
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_PARAM - Incorrect paramater
|
||||
SZ_ERROR_OUTPUT_EOF - output buffer overflow
|
||||
SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
|
||||
*/
|
||||
|
||||
SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
|
||||
const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
|
||||
ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,256 +0,0 @@
|
|||
/* Types.h -- Basic types
|
||||
2010-10-09 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_TYPES_H
|
||||
#define __7Z_TYPES_H
|
||||
|
||||
#include "../../UefiLzma.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifndef EXTERN_C_BEGIN
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN_C_BEGIN extern "C" {
|
||||
#define EXTERN_C_END }
|
||||
#else
|
||||
#define EXTERN_C_BEGIN
|
||||
#define EXTERN_C_END
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define SZ_OK 0
|
||||
|
||||
#define SZ_ERROR_DATA 1
|
||||
#define SZ_ERROR_MEM 2
|
||||
#define SZ_ERROR_CRC 3
|
||||
#define SZ_ERROR_UNSUPPORTED 4
|
||||
#define SZ_ERROR_PARAM 5
|
||||
#define SZ_ERROR_INPUT_EOF 6
|
||||
#define SZ_ERROR_OUTPUT_EOF 7
|
||||
#define SZ_ERROR_READ 8
|
||||
#define SZ_ERROR_WRITE 9
|
||||
#define SZ_ERROR_PROGRESS 10
|
||||
#define SZ_ERROR_FAIL 11
|
||||
#define SZ_ERROR_THREAD 12
|
||||
|
||||
#define SZ_ERROR_ARCHIVE 16
|
||||
#define SZ_ERROR_NO_ARCHIVE 17
|
||||
|
||||
typedef int SRes;
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef DWORD WRes;
|
||||
#else
|
||||
typedef int WRes;
|
||||
#endif
|
||||
|
||||
#ifndef RINOK
|
||||
#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
|
||||
#endif
|
||||
|
||||
typedef unsigned char Byte;
|
||||
typedef short Int16;
|
||||
typedef unsigned short UInt16;
|
||||
|
||||
#ifdef _LZMA_UINT32_IS_ULONG
|
||||
typedef long Int32;
|
||||
typedef unsigned long UInt32;
|
||||
#else
|
||||
typedef int Int32;
|
||||
typedef unsigned int UInt32;
|
||||
#endif
|
||||
|
||||
#ifdef _SZ_NO_INT_64
|
||||
|
||||
/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
|
||||
NOTES: Some code will work incorrectly in that case! */
|
||||
|
||||
typedef long Int64;
|
||||
typedef unsigned long UInt64;
|
||||
|
||||
#else
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
#define UINT64_CONST(n) n
|
||||
#else
|
||||
typedef long long int Int64;
|
||||
typedef unsigned long long int UInt64;
|
||||
#define UINT64_CONST(n) n ## ULL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _LZMA_NO_SYSTEM_SIZE_T
|
||||
typedef UInt32 SizeT;
|
||||
#else
|
||||
typedef size_t SizeT;
|
||||
#endif
|
||||
|
||||
typedef int Bool;
|
||||
#define True 1
|
||||
#define False 0
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MY_STD_CALL __stdcall
|
||||
#else
|
||||
#define MY_STD_CALL
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
#define MY_NO_INLINE __declspec(noinline)
|
||||
#else
|
||||
#define MY_NO_INLINE
|
||||
#endif
|
||||
|
||||
#define MY_CDECL __cdecl
|
||||
#define MY_FAST_CALL __fastcall
|
||||
|
||||
#else
|
||||
|
||||
#define MY_CDECL
|
||||
#define MY_FAST_CALL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* The following interfaces use first parameter as pointer to structure */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
|
||||
} IByteIn;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*Write)(void *p, Byte b);
|
||||
} IByteOut;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Read)(void *p, void *buf, size_t *size);
|
||||
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
|
||||
(output(*size) < input(*size)) is allowed */
|
||||
} ISeqInStream;
|
||||
|
||||
/* it can return SZ_ERROR_INPUT_EOF */
|
||||
SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
|
||||
SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
|
||||
SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t (*Write)(void *p, const void *buf, size_t size);
|
||||
/* Returns: result - the number of actually written bytes.
|
||||
(result < size) means error */
|
||||
} ISeqOutStream;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SZ_SEEK_SET = 0,
|
||||
SZ_SEEK_CUR = 1,
|
||||
SZ_SEEK_END = 2
|
||||
} ESzSeek;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
|
||||
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
|
||||
} ISeekInStream;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Look)(void *p, const void **buf, size_t *size);
|
||||
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
|
||||
(output(*size) > input(*size)) is not allowed
|
||||
(output(*size) < input(*size)) is allowed */
|
||||
SRes (*Skip)(void *p, size_t offset);
|
||||
/* offset must be <= output(*size) of Look */
|
||||
|
||||
SRes (*Read)(void *p, void *buf, size_t *size);
|
||||
/* reads directly (without buffer). It's same as ISeqInStream::Read */
|
||||
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
|
||||
} ILookInStream;
|
||||
|
||||
SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
|
||||
SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
|
||||
|
||||
/* reads via ILookInStream::Read */
|
||||
SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
|
||||
SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
|
||||
|
||||
#define LookToRead_BUF_SIZE (1 << 14)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ILookInStream s;
|
||||
ISeekInStream *realStream;
|
||||
size_t pos;
|
||||
size_t size;
|
||||
Byte buf[LookToRead_BUF_SIZE];
|
||||
} CLookToRead;
|
||||
|
||||
void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
|
||||
void LookToRead_Init(CLookToRead *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream s;
|
||||
ILookInStream *realStream;
|
||||
} CSecToLook;
|
||||
|
||||
void SecToLook_CreateVTable(CSecToLook *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream s;
|
||||
ILookInStream *realStream;
|
||||
} CSecToRead;
|
||||
|
||||
void SecToRead_CreateVTable(CSecToRead *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
|
||||
/* Returns: result. (result != SZ_OK) means break.
|
||||
Value (UInt64)(Int64)-1 for size means unknown value. */
|
||||
} ICompressProgress;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *(*Alloc)(void *p, size_t size);
|
||||
void (*Free)(void *p, void *address); /* address can be 0 */
|
||||
} ISzAlloc;
|
||||
|
||||
#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
|
||||
#define IAlloc_Free(p, a) (p)->Free((p), a)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define CHAR_PATH_SEPARATOR '\\'
|
||||
#define WCHAR_PATH_SEPARATOR L'\\'
|
||||
#define STRING_PATH_SEPARATOR "\\"
|
||||
#define WSTRING_PATH_SEPARATOR L"\\"
|
||||
|
||||
#else
|
||||
|
||||
#define CHAR_PATH_SEPARATOR '/'
|
||||
#define WCHAR_PATH_SEPARATOR L'/'
|
||||
#define STRING_PATH_SEPARATOR "/"
|
||||
#define WSTRING_PATH_SEPARATOR L"/"
|
||||
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
|
@ -1,31 +0,0 @@
|
|||
/* LZMA UEFI header file
|
||||
|
||||
Copyright (c) 2009, Intel Corporation. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __UEFILZMA_H__
|
||||
#define __UEFILZMA_H__
|
||||
|
||||
#include "../basetypes.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef _WIN32
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
#undef _WIN64
|
||||
#endif
|
||||
|
||||
#define _LZMA_SIZE_OPT
|
||||
#define _7ZIP_ST
|
||||
|
||||
#endif // __UEFILZMA_H__
|
||||
|
65
README.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
# UEFITool
|
||||
|
||||
UEFITool is a viewer and editor of firmware images conforming to UEFI Platform Interface (PI) Specifications.
|
||||
|
||||

|
||||
 [](https://scan.coverity.com/projects/17209) [](https://sonarcloud.io/summary/new_code?id=LongSoft_UEFITool)
|
||||
|
||||
|
||||
## Very Brief Introduction to UEFI
|
||||
|
||||
Unified Extensible Firmware Interface or UEFI is a post-BIOS firmware specification originally written by Intel for Itanium architecture and than adapted for X86 systems.
|
||||
The first EFI-compatible x86 firmwares were used on Apple Macintosh systems in 2006 and PC motherboard vendors started putting UEFI-compatible firmwares on their boards in 2011.
|
||||
In 2015 there are numerous systems using UEFI-compatible firmware including PCs, Macs, Tablets and Smartphones on x86, x86-64 and ARM architectures.
|
||||
More information on UEFI is available on [UEFI Forum official site](http://www.uefi.org/faq) and in [Wikipedia](http://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface).
|
||||
|
||||
## Very Brief Introduction to UEFITool
|
||||
|
||||
UEFITool is a cross-platform open source application written in C++/Qt, that parses UEFI-compatible firmware image into a tree structure, verifies image's integrity and provides a GUI to manipulate image's elements.
|
||||
Project development started in the middle of 2013 because of the lack of cross-platform open source utilities for tinkering with UEFI images.
|
||||
|
||||
In the beginning of 2015 the major refactoring round was started to make the program compatible with newer UEFI features including FFSv3 volumes and fixed image elements.
|
||||
It's in development right now with the following features still missing:
|
||||
* Editor part, i.e image reconstruction routines
|
||||
* Console UI
|
||||
|
||||
The missing parts are in development and the version with a new engine will be made as soon as image reconstruction works again.
|
||||
|
||||
## Derived projects
|
||||
|
||||
There are some other projects that use UEFITool's engine:
|
||||
* UEFIExtract, which uses ffsParser to parse supplied firmware image into a tree structure and dumps the parsed structure recursively on the FS. Jethro Beekman's [tree](https://github.com/jethrogb/uefireverse) utility can be used to work with the extracted tree.
|
||||
* UEFIFind, which uses ffsParser to find image elements containing a specified pattern. It was developed for [UBU](https://winraid.level1techs.com/t/tool-guide-news-uefi-bios-updater-ubu/30357) project.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Right now there are some alternatives to UEFITool that you could find useful too:
|
||||
* **[FMMT](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/Python/FMMT)** by TianoCore. Python-based open source toolset for modifying EDK2-based UEFI firmware images. Does not support any IBV customizations, but is _official_, and lives in EDK2 repository.
|
||||
* **[Fiano](https://github.com/linuxboot/fiano)** by Google and Facebook. Go-based cross-platform open source toolset for modifying UEFI firmware images.
|
||||
* **[PhoenixTool](https://forums.mydigitallife.net/threads/tool-to-insert-replace-slic-in-phoenix-insyde-dell-efi-bioses.13194)** by [AndyP](https://forums.mydigitallife.net/members/andyp.39295). Windows-only freeware GUI application written in C#. Used mostly for SLIC-related modifications, but it not limited to this task. Requires Microsoft .NET 3.5 to work properly. Supports unpacking firmware images from various vendor-specific formats like encrypted HP update files and Dell installers.
|
||||
* **[uefi-firmware-parser](https://github.com/theopolis/uefi-firmware-parser)** by [Teddy Reed](https://github.com/theopolis). Cross-platform open source console application written in Python. Very tinker-friendly due to use of Python. Can be used in scripts to automate firmware patching.
|
||||
* **[Chipsec](https://github.com/chipsec/chipsec)** by Intel. Cross-platform partially open source console application written in Python and C. Can be used to test Intel-based platforms for various security-related misconfigurations, but also has NVRAM parser and other components aimed to firmware modification.
|
||||
|
||||
## Installation
|
||||
|
||||
You can either use [pre-built binaries](https://github.com/LongSoft/UEFITool/releases) or build a binary yourself.
|
||||
* To build a binary that uses Qt library (UEFITool) you need a C++ compiler and an instance of [Qt5 or Qt6](https://www.qt.io) library. Install both of them, get the sources, generate makefiles using qmake (`qmake ./UEFITool/uefitool.pro`) and use your system's make command on that generated files (i.e. `nmake release`, `make release` and so on). Qt6-based builds can also use CMAKE as an altearnative build system.
|
||||
* To build a binary that doesn't use Qt (UEFIExtract, UEFIFind), you need a C++ compiler and [CMAKE](https://cmake.org) utility to generate a makefile for your OS and build environment. Install both of them, get the sources, generate makefiles using cmake (`cmake UEFIExtract`) and use your system's make command on that generated files (i.e. `nmake release`, `make release` and so on). Non-Qt builds can also use Meson as an alternative build system.
|
||||
|
||||
## Known issues
|
||||
|
||||
* Image editing is currently only possible using an outdated and unsupported UEFITool 0.28 (`old_engine` branch) and the tools based on it (`UEFIReplace`, `UEFIPatch`). This is the top priority [issue #67](https://github.com/LongSoft/UEFITool/issues/67), which is being worked on, albeit slowly (due to the amount of coding and testing required to implement it correctly).
|
||||
* Some vendor-specific firmware update files can be opened incorrectly or can't be opened at all. This includes encrypted HP update files, Dell HDR and EXE files, some InsydeFlash FD files and so on. Enabling support for such files will require massive amount of reverse-engineering which is almost pointless because the updated image can be obtained from BIOS chip where it's already decrypted and unpacked.
|
||||
* Intel Firmware Interface Table (FIT) editing is not supported right now. FIT contains pointers to various image components that must be loaded before executing the first CPU instruction from the BIOS chip. Those components include CPU microcode updates, binaries and settings used by BIOS Guard and Boot Guard technologies and some other stuff. More information on FIT can be obtained [here](https://edc.intel.com/content/www/us/en/design/products-and-solutions/software-and-services/firmware-and-bios/firmware-interface-table/firmware-interface-table/).
|
||||
* Windows builds of `UEFIExtract` and `UEFIFind` might encouter an issue with folder paths being longer than 260 bytes (`MAX_PATH`) on some input files (see [issue #363](https://github.com/LongSoft/UEFITool/issues/363)). This is a [known Windows limitation](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry), that can be fixed by enabling long paths support via Windows Registry and adding a manifest to the executable file that requires such support. `UEFIExtract` has the required manifest additions since version `A67`, and the required registry file is provided by Microsoft on the page linked above, but this workaround is only awailable starting with Windows 10 build 1067.
|
||||
|
||||
## Bug repellents
|
||||
|
||||
* [Coverity Scan](https://scan.coverity.com/projects/17209) - static analyzer for C, C++, C#, JavaScript, Ruby, or Python code.
|
||||
* [SonarCloud](https://sonarcloud.io/project/overview?id=LongSoft_UEFITool) - cloud-based source code analysis service.
|
||||
|
||||
## GUID Database
|
||||
|
||||
Every new release includes an update to the database of known UEFI-related GUIDs build with help of [Linux Vendor Firmware Service](https://fwupd.org).
|
||||
|
||||
You can download the up-to-date version of that database using [this link](https://fwupd.org/lvfs/shards/export/csv).
|
44
README.rst
|
@ -1,44 +0,0 @@
|
|||
UEFITool
|
||||
========
|
||||
.. image:: https://raw.githubusercontent.com/LongSoft/UEFITool/master/uefitool.ico
|
||||
.. image:: https://scan.coverity.com/projects/1812/badge.svg?flat=1
|
||||
:target: https://scan.coverity.com/projects/1812/
|
||||
|
||||
|
|
||||
| UEFITool is a cross-platform C++/Qt program for parsing, extracting and modifying UEFI firmware images.
|
||||
| It supports parsing of full BIOS images starting with the flash descriptor or any binary files containing UEFI volumes.
|
||||
| Original development was started `here <http://forums.mydigitallife.info/threads/48979-UEFITool-UEFI-firmware-image-viewer-and-editor>`_ at MDL forums as a cross-platform analog to `PhoenixTool <http://forums.mydigitallife.info/threads/13194-Tool-to-Insert-Replace-SLIC-in-Phoenix-Insyde-Dell-EFI-BIOSes>`_'s structure mode with some additional features, but the program's engine was proven to be usefull for another projects like `UEFIPatch <http://www.insanelymac.com/forum/topic/285444-uefipatch-uefi-patching-utility/>`_, `UBU <http://www.win-raid.com/t154f16-Tool-quot-UEFI-BIOS-Updater-quot-UBU.html>`_ and `OZMTool <http://www.insanelymac.com/forum/topic/299711-ozmtool-an-ozmosis-toolbox/>`_.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
| You can either use `pre-built binaries for Windows and OSX <https://github.com/LongSoft/UEFITool/releases/latest>`_ or build a binary yourself.
|
||||
| To build a binary you need a C++ compiler and an instance of Qt4/Qt5 library for it.
|
||||
| Install both of them, get the sources, generate makefiles using qmake (*qmake UEFITool.pro*) and use your make command on that generated files (i.e. *nmake release*, *make release* and so on).
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
| The program can be started directly without any arguments or supplied with a single argument - a path to the UEFI image file to open after start.
|
||||
|
|
||||
| The program window is divided into three panels: **Structure**, **Information** and **Messages**.
|
||||
| Structure of the image is represented as a tree of elements with different names, types and subtypes. If you select an element, **Information** panel will show the available information about the selected element based on it's type and contents.
|
||||
| **Messages** panel show all messages from the engine, including structure warnings and search results. Most of messages can be double-clicked to select the element that causes the message.
|
||||
|
|
||||
| You can open a menu on each tree element to see what operations are possible for the selected element. This can include various types of **Extract**, **Insert** and **Replace** operations, as well as **Remove** and **Rebuild**.
|
||||
| **Extract** has two variants: **Extract as is** and **Extract body**. The difference is that **Extract as is** extracts the element with it's header (GUID, size, attributes and other structure-related information are located there), and **Extract body** extracts the element data only.
|
||||
| **Replace** has the same two variants as **Extract** with the same meaning.
|
||||
| **Insert** has the three different variants: **Insert before**, **Insert after** and **Insert into**, which is only available for UEFI volumes and encapsulation sections.
|
||||
| **Remove** marks an element for removal on image reconstuction.
|
||||
| **Rebuild** marks an element for rebuilding on image reconstruction. Normally, all elements that aren't marked for rebuild won't be changed at all and if you need to correct some structure error (i.e. invalid data checksum) you must mark an element for rebuild manually. If you change an element all it's parents up to the tree root will be marked for rebuild automatically. If UEFI volume is marked for rebuild all uncompressed PEI files in it will also be marked for rebuild because they must be rebased in the reconstructed image to maintain the executable-in-place constraint.
|
||||
|
|
||||
| There is also a search function available from the *File* menu, you can search all tree elements for a specified hexadecimal pattern (spaces are not counted, dot symbol (.) is used as placeholder for a single hex digit), a specified GUID (rules are the same as for hex except for spaces) and a specified text (either Unicode or ASCII, case sensitive or not). Search results will be added into **Messages** panel, if anything is found.
|
||||
|
|
||||
| After you've finished the modifications, you need to initiate image reconstruction using *Save image file* command from the *File* menu. If anything goes wrong on the reconstruction, an error will pop up, otherwise the program will prompt if you need to open the reconstructed file. Don't rush it, because reconstruction process can also generate some usefull messages, which will be lost if you open the reconstructed file immediatelly.
|
||||
|
||||
Known issues
|
||||
------------
|
||||
* Some images has non-standard calculation of base address of TE images, so the program can rebase them incorrectly after modifications. Will be solved ASAP.
|
||||
* Some images may not work after modification because of no FIT table support implemented yet. It's on my high priority features list, so I hope it will be corrected soon.
|
||||
* The program is meant to work with BIOS images, not some vendor-specific BIOS update files, that is why some of that update file either can\t be opened at all or return errors on reconstruction. If someone wants to write an unpacker for such crappy files - I will be glad to use it.
|
||||
* AMI-specific features like NCBs, ROM_AREA structure and other things like that can't be implemented by me because of the NDA I have.
|
|
@ -1,998 +0,0 @@
|
|||
/*++ EfiTianoDecompress.c
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.<BR>
|
||||
Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Decompress.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Decompressor. Algorithm Ported from OPSD code (Decomp.asm)
|
||||
|
||||
--*/
|
||||
|
||||
#include "EfiTianoDecompress.h"
|
||||
|
||||
//
|
||||
// Decompression algorithm begins here
|
||||
//
|
||||
#define BITBUFSIZ 32
|
||||
#define MAXMATCH 256
|
||||
#define THRESHOLD 3
|
||||
#define CODE_BIT 16
|
||||
#ifndef UINT8_MAX
|
||||
#define UINT8_MAX 0xff
|
||||
#endif
|
||||
#define BAD_TABLE - 1
|
||||
|
||||
//
|
||||
// C: Char&Len Set; P: Position Set; T: exTra Set
|
||||
//
|
||||
#define NC (0xff + MAXMATCH + 2 - THRESHOLD)
|
||||
#define CBIT 9
|
||||
#define MAXPBIT 5
|
||||
#define TBIT 5
|
||||
#define MAXNP ((1U << MAXPBIT) - 1)
|
||||
#define NT (CODE_BIT + 3)
|
||||
#if NT > MAXNP
|
||||
#define NPT NT
|
||||
#else
|
||||
#define NPT MAXNP
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
UINT8 *mSrcBase; // Starting address of compressed data
|
||||
UINT8 *mDstBase; // Starting address of decompressed data
|
||||
UINT32 mOutBuf;
|
||||
UINT32 mInBuf;
|
||||
|
||||
UINT16 mBitCount;
|
||||
UINT32 mBitBuf;
|
||||
UINT32 mSubBitBuf;
|
||||
UINT16 mBlockSize;
|
||||
UINT32 mCompSize;
|
||||
UINT32 mOrigSize;
|
||||
|
||||
UINT16 mBadTableFlag;
|
||||
|
||||
UINT16 mLeft[2 * NC - 1];
|
||||
UINT16 mRight[2 * NC - 1];
|
||||
UINT8 mCLen[NC];
|
||||
UINT8 mPTLen[NPT];
|
||||
UINT16 mCTable[4096];
|
||||
UINT16 mPTTable[256];
|
||||
|
||||
//
|
||||
// The length of the field 'Position Set Code Length Array Size' in Block Header.
|
||||
// For EFI 1.1 de/compression algorithm, mPBit = 4
|
||||
// For Tiano de/compression algorithm, mPBit = 5
|
||||
//
|
||||
UINT8 mPBit;
|
||||
} SCRATCH_DATA;
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
FillBuf(
|
||||
IN SCRATCH_DATA *Sd,
|
||||
IN UINT16 NumOfBits
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source.
|
||||
|
||||
Arguments:
|
||||
|
||||
Sd - The global scratch data
|
||||
NumOfBits - The number of bits to shift and read.
|
||||
|
||||
Returns: (VOID)
|
||||
|
||||
--*/
|
||||
{
|
||||
Sd->mBitBuf = (UINT32)(Sd->mBitBuf << NumOfBits);
|
||||
|
||||
while (NumOfBits > Sd->mBitCount) {
|
||||
Sd->mBitBuf |= (UINT32)(Sd->mSubBitBuf << (NumOfBits = (UINT16)(NumOfBits - Sd->mBitCount)));
|
||||
|
||||
if (Sd->mCompSize > 0) {
|
||||
//
|
||||
// Get 1 byte into SubBitBuf
|
||||
//
|
||||
Sd->mCompSize--;
|
||||
Sd->mSubBitBuf = 0;
|
||||
Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++];
|
||||
Sd->mBitCount = 8;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// No more bits from the source, just pad zero bit.
|
||||
//
|
||||
Sd->mSubBitBuf = 0;
|
||||
Sd->mBitCount = 8;
|
||||
}
|
||||
}
|
||||
|
||||
Sd->mBitCount = (UINT16)(Sd->mBitCount - NumOfBits);
|
||||
Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount;
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT32
|
||||
GetBits(
|
||||
IN SCRATCH_DATA *Sd,
|
||||
IN UINT16 NumOfBits
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent
|
||||
NumOfBits of bits from source. Returns NumOfBits of bits that are
|
||||
popped out.
|
||||
|
||||
Arguments:
|
||||
|
||||
Sd - The global scratch data.
|
||||
NumOfBits - The number of bits to pop and read.
|
||||
|
||||
Returns:
|
||||
|
||||
The bits that are popped out.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT32 OutBits;
|
||||
|
||||
OutBits = (UINT32)(Sd->mBitBuf >> (BITBUFSIZ - NumOfBits));
|
||||
|
||||
FillBuf(Sd, NumOfBits);
|
||||
|
||||
return OutBits;
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT16
|
||||
MakeTable(
|
||||
IN SCRATCH_DATA *Sd,
|
||||
IN UINT16 NumOfChar,
|
||||
IN UINT8 *BitLen,
|
||||
IN UINT16 TableBits,
|
||||
OUT UINT16 *Table
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Creates Huffman Code mapping table according to code length array.
|
||||
|
||||
Arguments:
|
||||
|
||||
Sd - The global scratch data
|
||||
NumOfChar - Number of symbols in the symbol set
|
||||
BitLen - Code length array
|
||||
TableBits - The width of the mapping table
|
||||
Table - The table
|
||||
|
||||
Returns:
|
||||
|
||||
0 - OK.
|
||||
BAD_TABLE - The table is corrupted.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT16 Count[17];
|
||||
UINT16 Weight[17];
|
||||
UINT16 Start[18];
|
||||
UINT16 *Pointer;
|
||||
UINT16 Index3;
|
||||
UINT16 Index;
|
||||
UINT16 Len;
|
||||
UINT16 Char;
|
||||
UINT16 JuBits;
|
||||
UINT16 Avail;
|
||||
UINT16 NextCode;
|
||||
UINT16 Mask;
|
||||
|
||||
//
|
||||
// TableBits should not be greater than 16.
|
||||
//
|
||||
if (TableBits >= (sizeof(Count) / sizeof(UINT16))) {
|
||||
return (UINT16)BAD_TABLE;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize Count array starting from Index 0, as there is a possibility of Count array being uninitialized.
|
||||
//
|
||||
for (Index = 0; Index <= 16; Index++) {
|
||||
Count[Index] = 0;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < NumOfChar; Index++) {
|
||||
//
|
||||
// Count array index should not be greater than or equal to its size.
|
||||
//
|
||||
if (BitLen[Index] < (sizeof(Count) / sizeof(UINT16))) {
|
||||
Count[BitLen[Index]]++;
|
||||
}
|
||||
else {
|
||||
return (UINT16)BAD_TABLE;
|
||||
}
|
||||
}
|
||||
|
||||
Start[0] = 0;
|
||||
Start[1] = 0;
|
||||
|
||||
for (Index = 1; Index <= 16; Index++) {
|
||||
Start[Index + 1] = (UINT16)(Start[Index] + (Count[Index] << (16 - Index)));
|
||||
}
|
||||
|
||||
if (Start[17] != 0) {
|
||||
/*(1U << 16)*/
|
||||
return (UINT16)BAD_TABLE;
|
||||
}
|
||||
|
||||
JuBits = (UINT16)(16 - TableBits);
|
||||
|
||||
for (Index = 1; Index <= TableBits; Index++) {
|
||||
Start[Index] >>= JuBits;
|
||||
Weight[Index] = (UINT16)(1U << (TableBits - Index));
|
||||
}
|
||||
|
||||
while (Index <= 16) {
|
||||
Weight[Index] = (UINT16)(1U << (16 - Index));
|
||||
Index++;
|
||||
}
|
||||
|
||||
Index = (UINT16)(Start[TableBits + 1] >> JuBits);
|
||||
|
||||
if (Index != 0) {
|
||||
Index3 = (UINT16)(1U << TableBits);
|
||||
while (Index != Index3) {
|
||||
Table[Index++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Avail = NumOfChar;
|
||||
Mask = (UINT16)(1U << (15 - TableBits));
|
||||
|
||||
for (Char = 0; Char < NumOfChar; Char++) {
|
||||
Len = BitLen[Char];
|
||||
if (Len == 0 || Len >= 17) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NextCode = (UINT16)(Start[Len] + Weight[Len]);
|
||||
|
||||
if (Len <= TableBits) {
|
||||
for (Index = Start[Len]; Index < NextCode; Index++) {
|
||||
// Check to prevent possible heap corruption
|
||||
if (Index >= (UINT16)(1U << TableBits))
|
||||
return (UINT16)BAD_TABLE;
|
||||
Table[Index] = Char;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Index3 = Start[Len];
|
||||
Pointer = &Table[Index3 >> JuBits];
|
||||
Index = (UINT16)(Len - TableBits);
|
||||
|
||||
while (Index != 0) {
|
||||
//
|
||||
// Avail should be lesser than size of mRight and mLeft to prevent buffer overflow.
|
||||
//
|
||||
if ((*Pointer == 0) && (Avail < sizeof(Sd->mRight) / sizeof(UINT16)) && (Avail < sizeof(Sd->mLeft) / sizeof(UINT16))) {
|
||||
Sd->mRight[Avail] = Sd->mLeft[Avail] = 0;
|
||||
*Pointer = Avail++;
|
||||
}
|
||||
|
||||
//
|
||||
// *Pointer should be lesser than size of mRight and mLeft to prevent buffer overflow.
|
||||
//
|
||||
if ((Index3 & Mask) && (*Pointer < (sizeof(Sd->mRight) / sizeof(UINT16)))) {
|
||||
Pointer = &Sd->mRight[*Pointer];
|
||||
}
|
||||
else if (*Pointer < (sizeof(Sd->mLeft) / sizeof(UINT16))) {
|
||||
Pointer = &Sd->mLeft[*Pointer];
|
||||
}
|
||||
|
||||
Index3 <<= 1;
|
||||
Index--;
|
||||
}
|
||||
|
||||
*Pointer = Char;
|
||||
}
|
||||
|
||||
Start[Len] = NextCode;
|
||||
}
|
||||
//
|
||||
// Succeeds
|
||||
//
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT32
|
||||
DecodeP(
|
||||
IN SCRATCH_DATA *Sd
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decodes a position value.
|
||||
|
||||
Arguments:
|
||||
|
||||
Sd - the global scratch data
|
||||
|
||||
Returns:
|
||||
|
||||
The position value decoded.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT16 Val;
|
||||
UINT32 Mask;
|
||||
UINT32 Pos;
|
||||
|
||||
Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)];
|
||||
|
||||
if (Val >= MAXNP) {
|
||||
Mask = 1U << (BITBUFSIZ - 1 - 8);
|
||||
|
||||
do {
|
||||
if (Sd->mBitBuf & Mask) {
|
||||
Val = Sd->mRight[Val];
|
||||
}
|
||||
else {
|
||||
Val = Sd->mLeft[Val];
|
||||
}
|
||||
|
||||
Mask >>= 1;
|
||||
} while (Val >= MAXNP);
|
||||
}
|
||||
//
|
||||
// Advance what we have read
|
||||
//
|
||||
FillBuf(Sd, Sd->mPTLen[Val]);
|
||||
|
||||
Pos = Val;
|
||||
if (Val > 1) {
|
||||
Pos = (UINT32)((1U << (Val - 1)) + GetBits(Sd, (UINT16)(Val - 1)));
|
||||
}
|
||||
|
||||
return Pos;
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT16
|
||||
ReadPTLen(
|
||||
IN SCRATCH_DATA *Sd,
|
||||
IN UINT16 nn,
|
||||
IN UINT16 nbit,
|
||||
IN UINT16 Special
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Reads code lengths for the Extra Set or the Position Set
|
||||
|
||||
Arguments:
|
||||
|
||||
Sd - The global scratch data
|
||||
nn - Number of symbols
|
||||
nbit - Number of bits needed to represent nn
|
||||
Special - The special symbol that needs to be taken care of
|
||||
|
||||
Returns:
|
||||
|
||||
0 - OK.
|
||||
BAD_TABLE - Table is corrupted.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT16 Number;
|
||||
UINT16 CharC;
|
||||
UINT16 Index;
|
||||
UINT32 Mask;
|
||||
|
||||
Number = (UINT16)GetBits(Sd, nbit);
|
||||
|
||||
if ((Number > sizeof(Sd->mPTLen)) || (nn > sizeof(Sd->mPTLen))) {
|
||||
//
|
||||
// Fail if Number or nn is greater than size of mPTLen
|
||||
//
|
||||
return (UINT16)BAD_TABLE;
|
||||
}
|
||||
|
||||
if (Number == 0) {
|
||||
CharC = (UINT16)GetBits(Sd, nbit);
|
||||
|
||||
for (Index = 0; Index < 256; Index++) {
|
||||
Sd->mPTTable[Index] = CharC;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < nn; Index++) {
|
||||
Sd->mPTLen[Index] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Index = 0;
|
||||
|
||||
while (Index < Number) {
|
||||
CharC = (UINT16)(Sd->mBitBuf >> (BITBUFSIZ - 3));
|
||||
|
||||
if (CharC == 7) {
|
||||
Mask = 1U << (BITBUFSIZ - 1 - 3);
|
||||
while (Mask & Sd->mBitBuf) {
|
||||
Mask >>= 1;
|
||||
CharC += 1;
|
||||
}
|
||||
}
|
||||
|
||||
FillBuf(Sd, (UINT16)((CharC < 7) ? 3 : CharC - 3));
|
||||
|
||||
Sd->mPTLen[Index++] = (UINT8)CharC;
|
||||
|
||||
if (Index == Special) {
|
||||
CharC = (UINT16)GetBits(Sd, 2);
|
||||
while ((INT16)(--CharC) >= 0) {
|
||||
if (Index >= sizeof(Sd->mPTLen)) {
|
||||
//
|
||||
// Fail if Index is greater than or equal to mPTLen
|
||||
//
|
||||
return (UINT16)BAD_TABLE;
|
||||
}
|
||||
Sd->mPTLen[Index++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (Index < nn) {
|
||||
Sd->mPTLen[Index++] = 0;
|
||||
}
|
||||
|
||||
return MakeTable(Sd, nn, Sd->mPTLen, 8, Sd->mPTTable);
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
ReadCLen(
|
||||
SCRATCH_DATA *Sd
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Reads code lengths for Char&Len Set.
|
||||
|
||||
Arguments:
|
||||
|
||||
Sd - the global scratch data
|
||||
|
||||
Returns: (VOID)
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT16 Number;
|
||||
UINT16 CharC;
|
||||
UINT16 Index;
|
||||
UINT32 Mask;
|
||||
|
||||
Number = (UINT16)GetBits(Sd, CBIT);
|
||||
|
||||
if (Number == 0) {
|
||||
CharC = (UINT16)GetBits(Sd, CBIT);
|
||||
|
||||
for (Index = 0; Index < NC; Index++) {
|
||||
Sd->mCLen[Index] = 0;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < 4096; Index++) {
|
||||
Sd->mCTable[Index] = CharC;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Index = 0;
|
||||
while (Index < Number) {
|
||||
CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)];
|
||||
if (CharC >= NT) {
|
||||
Mask = 1U << (BITBUFSIZ - 1 - 8);
|
||||
|
||||
do {
|
||||
if (Mask & Sd->mBitBuf) {
|
||||
CharC = Sd->mRight[CharC];
|
||||
}
|
||||
else {
|
||||
CharC = Sd->mLeft[CharC];
|
||||
}
|
||||
|
||||
Mask >>= 1;
|
||||
} while (CharC >= NT);
|
||||
}
|
||||
//
|
||||
// Advance what we have read
|
||||
//
|
||||
FillBuf(Sd, Sd->mPTLen[CharC]);
|
||||
|
||||
if (CharC <= 2) {
|
||||
if (CharC == 0) {
|
||||
CharC = 1;
|
||||
}
|
||||
else if (CharC == 1) {
|
||||
CharC = (UINT16)(GetBits(Sd, 4) + 3);
|
||||
}
|
||||
else if (CharC == 2) {
|
||||
CharC = (UINT16)(GetBits(Sd, CBIT) + 20);
|
||||
}
|
||||
|
||||
while ((INT16)(--CharC) >= 0) {
|
||||
Sd->mCLen[Index++] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Sd->mCLen[Index++] = (UINT8)(CharC - 2);
|
||||
}
|
||||
}
|
||||
|
||||
while (Index < NC) {
|
||||
Sd->mCLen[Index++] = 0;
|
||||
}
|
||||
|
||||
MakeTable(Sd, NC, Sd->mCLen, 12, Sd->mCTable);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT16
|
||||
DecodeC(
|
||||
SCRATCH_DATA *Sd
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decode a character/length value.
|
||||
|
||||
Arguments:
|
||||
|
||||
Sd - The global scratch data.
|
||||
|
||||
Returns:
|
||||
|
||||
The value decoded.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT16 Index2;
|
||||
UINT32 Mask;
|
||||
|
||||
if (Sd->mBlockSize == 0) {
|
||||
//
|
||||
// Starting a new block
|
||||
//
|
||||
Sd->mBlockSize = (UINT16)GetBits(Sd, 16);
|
||||
Sd->mBadTableFlag = ReadPTLen(Sd, NT, TBIT, 3);
|
||||
if (Sd->mBadTableFlag != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ReadCLen(Sd);
|
||||
|
||||
Sd->mBadTableFlag = ReadPTLen(Sd, MAXNP, Sd->mPBit, (UINT16)(-1));
|
||||
if (Sd->mBadTableFlag != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Sd->mBlockSize--;
|
||||
Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)];
|
||||
|
||||
if (Index2 >= NC) {
|
||||
Mask = 1U << (BITBUFSIZ - 1 - 12);
|
||||
|
||||
do {
|
||||
if (Sd->mBitBuf & Mask) {
|
||||
Index2 = Sd->mRight[Index2];
|
||||
}
|
||||
else {
|
||||
Index2 = Sd->mLeft[Index2];
|
||||
}
|
||||
|
||||
Mask >>= 1;
|
||||
} while (Index2 >= NC);
|
||||
}
|
||||
//
|
||||
// Advance what we have read
|
||||
//
|
||||
FillBuf(Sd, Sd->mCLen[Index2]);
|
||||
|
||||
return Index2;
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
Decode(
|
||||
SCRATCH_DATA *Sd
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decode the source data and put the resulting data into the destination buffer.
|
||||
|
||||
Arguments:
|
||||
|
||||
Sd - The global scratch data
|
||||
|
||||
Returns: (VOID)
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT16 BytesRemain;
|
||||
UINT32 DataIdx;
|
||||
UINT16 CharC;
|
||||
|
||||
BytesRemain = (UINT16)(-1);
|
||||
|
||||
DataIdx = 0;
|
||||
|
||||
for (;;) {
|
||||
CharC = DecodeC(Sd);
|
||||
if (Sd->mBadTableFlag != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CharC < 256) {
|
||||
//
|
||||
// Process an Original character
|
||||
//
|
||||
if (Sd->mOutBuf >= Sd->mOrigSize) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
Sd->mDstBase[Sd->mOutBuf++] = (UINT8)CharC;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Process a Pointer
|
||||
//
|
||||
CharC = (UINT16)(CharC - (UINT8_MAX + 1 - THRESHOLD));
|
||||
|
||||
BytesRemain = CharC;
|
||||
|
||||
DataIdx = Sd->mOutBuf - DecodeP(Sd) - 1;
|
||||
|
||||
// Check to prevent possible heap corruption
|
||||
if (DataIdx >= Sd->mOrigSize - BytesRemain) {
|
||||
Sd->mBadTableFlag = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
BytesRemain--;
|
||||
while ((INT16)(BytesRemain) >= 0) {
|
||||
Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++];
|
||||
if (Sd->mOutBuf >= Sd->mOrigSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
BytesRemain--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
GetInfo(
|
||||
IN const VOID *Source,
|
||||
IN UINT32 SrcSize,
|
||||
OUT UINT32 *DstSize,
|
||||
OUT UINT32 *ScratchSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The internal implementation of *_DECOMPRESS_PROTOCOL.GetInfo().
|
||||
|
||||
Arguments:
|
||||
|
||||
Source - The source buffer containing the compressed data.
|
||||
SrcSize - The size of source buffer
|
||||
DstSize - The size of destination buffer.
|
||||
ScratchSize - The size of scratch buffer.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved.
|
||||
EFI_INVALID_PARAMETER - The source data is corrupted
|
||||
|
||||
--*/
|
||||
{
|
||||
const UINT8 *Src;
|
||||
|
||||
*ScratchSize = sizeof(SCRATCH_DATA);
|
||||
|
||||
Src = Source;
|
||||
if (SrcSize < 8) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*DstSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
Decompress(
|
||||
IN const VOID *Source,
|
||||
IN UINT32 SrcSize,
|
||||
IN OUT VOID *Destination,
|
||||
IN UINT32 DstSize,
|
||||
IN OUT VOID *Scratch,
|
||||
IN UINT32 ScratchSize,
|
||||
IN UINT8 Version
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The internal implementation of *_DECOMPRESS_PROTOCOL.Decompress().
|
||||
|
||||
Arguments:
|
||||
|
||||
Source - The source buffer containing the compressed data.
|
||||
SrcSize - The size of source buffer
|
||||
Destination - The destination buffer to store the decompressed data
|
||||
DstSize - The size of destination buffer.
|
||||
Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
|
||||
ScratchSize - The size of scratch buffer.
|
||||
Version - The version of de/compression algorithm.
|
||||
Version 1 for EFI 1.1 de/compression algorithm.
|
||||
Version 2 for Tiano de/compression algorithm.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS - Decompression is successful
|
||||
EFI_INVALID_PARAMETER - The source data is corrupted
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT32 Index;
|
||||
UINT32 CompSize;
|
||||
UINT32 OrigSize;
|
||||
EFI_STATUS Status;
|
||||
SCRATCH_DATA *Sd;
|
||||
const UINT8 *Src;
|
||||
UINT8 *Dst;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
Src = Source;
|
||||
Dst = Destination;
|
||||
|
||||
if (ScratchSize < sizeof(SCRATCH_DATA)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Sd = (SCRATCH_DATA *)Scratch;
|
||||
|
||||
if (SrcSize < 8) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24);
|
||||
OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
|
||||
|
||||
//
|
||||
// If compressed file size is 0, return
|
||||
//
|
||||
if (OrigSize == 0) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (SrcSize < CompSize + 8) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (DstSize != OrigSize) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Src = Src + 8;
|
||||
|
||||
for (Index = 0; Index < sizeof(SCRATCH_DATA); Index++) {
|
||||
((UINT8 *)Sd)[Index] = 0;
|
||||
}
|
||||
//
|
||||
// The length of the field 'Position Set Code Length Array Size' in Block Header.
|
||||
// For EFI 1.1 de/compression algorithm(Version 1), mPBit = 4
|
||||
// For Tiano de/compression algorithm(Version 2), mPBit = 5
|
||||
//
|
||||
switch (Version) {
|
||||
case 1:
|
||||
Sd->mPBit = 4;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
Sd->mPBit = 5;
|
||||
break;
|
||||
|
||||
default:
|
||||
//
|
||||
// Currently, only have 2 versions
|
||||
//
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Sd->mSrcBase = (UINT8*)Src;
|
||||
Sd->mDstBase = Dst;
|
||||
Sd->mCompSize = CompSize;
|
||||
Sd->mOrigSize = OrigSize;
|
||||
|
||||
//
|
||||
// Fill the first BITBUFSIZ bits
|
||||
//
|
||||
FillBuf(Sd, BITBUFSIZ);
|
||||
|
||||
//
|
||||
// Decompress it
|
||||
//
|
||||
Decode(Sd);
|
||||
|
||||
if (Sd->mBadTableFlag != 0) {
|
||||
//
|
||||
// Something wrong with the source
|
||||
//
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiTianoGetInfo(
|
||||
IN const VOID *Source,
|
||||
IN UINT32 SrcSize,
|
||||
OUT UINT32 *DstSize,
|
||||
OUT UINT32 *ScratchSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The implementation of EFI_DECOMPRESS_PROTOCOL.GetInfo().
|
||||
|
||||
Arguments:
|
||||
|
||||
This - The protocol instance pointer
|
||||
Source - The source buffer containing the compressed data.
|
||||
SrcSize - The size of source buffer
|
||||
DstSize - The size of destination buffer.
|
||||
ScratchSize - The size of scratch buffer.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successful retrieved.
|
||||
EFI_INVALID_PARAMETER - The source data is corrupted
|
||||
|
||||
--*/
|
||||
{
|
||||
return GetInfo(
|
||||
Source,
|
||||
SrcSize,
|
||||
DstSize,
|
||||
ScratchSize
|
||||
);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiDecompress(
|
||||
IN const VOID *Source,
|
||||
IN UINT32 SrcSize,
|
||||
IN OUT VOID *Destination,
|
||||
IN UINT32 DstSize,
|
||||
IN OUT VOID *Scratch,
|
||||
IN UINT32 ScratchSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The implementation of EFI_DECOMPRESS_PROTOCOL.Decompress().
|
||||
|
||||
Arguments:
|
||||
|
||||
This - The protocol instance pointer
|
||||
Source - The source buffer containing the compressed data.
|
||||
SrcSize - The size of source buffer
|
||||
Destination - The destination buffer to store the decompressed data
|
||||
DstSize - The size of destination buffer.
|
||||
Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
|
||||
ScratchSize - The size of scratch buffer.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS - Decompression is successful
|
||||
EFI_INVALID_PARAMETER - The source data is corrupted
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// For EFI 1.1 de/compression algorithm, the version is 1.
|
||||
//
|
||||
return Decompress(
|
||||
Source,
|
||||
SrcSize,
|
||||
Destination,
|
||||
DstSize,
|
||||
Scratch,
|
||||
ScratchSize,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
TianoDecompress(
|
||||
IN const VOID *Source,
|
||||
IN UINT32 SrcSize,
|
||||
IN OUT VOID *Destination,
|
||||
IN UINT32 DstSize,
|
||||
IN OUT VOID *Scratch,
|
||||
IN UINT32 ScratchSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The implementation of EFI_TIANO_DECOMPRESS_PROTOCOL.Decompress().
|
||||
|
||||
Arguments:
|
||||
|
||||
This - The protocol instance pointer
|
||||
Source - The source buffer containing the compressed data.
|
||||
SrcSize - The size of source buffer
|
||||
Destination - The destination buffer to store the decompressed data
|
||||
DstSize - The size of destination buffer.
|
||||
Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
|
||||
ScratchSize - The size of scratch buffer.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS - Decompression is successful
|
||||
EFI_INVALID_PARAMETER - The source data is corrupted
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// For Tiano de/compression algorithm, the version is 2.
|
||||
//
|
||||
return Decompress(
|
||||
Source,
|
||||
SrcSize,
|
||||
Destination,
|
||||
DstSize,
|
||||
Scratch,
|
||||
ScratchSize,
|
||||
2
|
||||
);
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
/* EfiTianoDecompress.h
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.<BR>
|
||||
Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
Module Name:
|
||||
|
||||
Decompress.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Header file for decompression routine.
|
||||
Providing both EFI and Tiano decompress algorithms.
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _EFITIANODECOMPRESS_H_
|
||||
#define _EFITIANODECOMPRESS_H_
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../basetypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
UINT32 CompSize;
|
||||
UINT32 OrigSize;
|
||||
} EFI_TIANO_HEADER;
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiTianoGetInfo(
|
||||
const VOID *Source,
|
||||
UINT32 SrcSize,
|
||||
UINT32 *DstSize,
|
||||
UINT32 *ScratchSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The implementation is same as that of EFI_DECOMPRESS_PROTOCOL.GetInfo().
|
||||
|
||||
Arguments:
|
||||
|
||||
This - The protocol instance pointer
|
||||
Source - The source buffer containing the compressed data.
|
||||
SrcSize - The size of source buffer
|
||||
DstSize - The size of destination buffer.
|
||||
ScratchSize - The size of scratch buffer.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successfully retrieved.
|
||||
EFI_INVALID_PARAMETER - The source data is corrupted
|
||||
|
||||
--*/
|
||||
;
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EfiDecompress(
|
||||
const VOID *Source,
|
||||
UINT32 SrcSize,
|
||||
VOID *Destination,
|
||||
UINT32 DstSize,
|
||||
VOID *Scratch,
|
||||
UINT32 ScratchSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The implementation is same as that of EFI_DECOMPRESS_PROTOCOL.Decompress().
|
||||
|
||||
Arguments:
|
||||
|
||||
This - The protocol instance pointer
|
||||
Source - The source buffer containing the compressed data.
|
||||
SrcSize - The size of source buffer
|
||||
Destination - The destination buffer to store the decompressed data
|
||||
DstSize - The size of destination buffer.
|
||||
Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
|
||||
ScratchSize - The size of scratch buffer.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS - Decompression is successful
|
||||
EFI_INVALID_PARAMETER - The source data is corrupted
|
||||
|
||||
--*/
|
||||
;
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
TianoDecompress(
|
||||
const VOID *Source,
|
||||
UINT32 SrcSize,
|
||||
VOID *Destination,
|
||||
UINT32 DstSize,
|
||||
VOID *Scratch,
|
||||
UINT32 ScratchSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The implementation is same as that of EFI_TIANO_DECOMPRESS_PROTOCOL.Decompress().
|
||||
|
||||
Arguments:
|
||||
|
||||
This - The protocol instance pointer
|
||||
Source - The source buffer containing the compressed data.
|
||||
SrcSize - The size of source buffer
|
||||
Destination - The destination buffer to store the decompressed data
|
||||
DstSize - The size of destination buffer.
|
||||
Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
|
||||
ScratchSize - The size of scratch buffer.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS - Decompression is successful
|
||||
EFI_INVALID_PARAMETER - The source data is corrupted
|
||||
|
||||
--*/
|
||||
;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
92
UEFIExtract/CMakeLists.txt
Normal file
|
@ -0,0 +1,92 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 3.22)
|
||||
|
||||
PROJECT(UEFIExtract)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
SET(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
SET(PROJECT_SOURCES
|
||||
uefiextract_main.cpp
|
||||
ffsdumper.cpp
|
||||
uefidump.cpp
|
||||
../common/guiddatabase.cpp
|
||||
../common/types.cpp
|
||||
../common/filesystem.cpp
|
||||
../common/descriptor.cpp
|
||||
../common/ffs.cpp
|
||||
../common/nvram.cpp
|
||||
../common/nvramparser.cpp
|
||||
../common/meparser.cpp
|
||||
../common/ffsparser.cpp
|
||||
../common/fitparser.cpp
|
||||
../common/ffsreport.cpp
|
||||
../common/peimage.cpp
|
||||
../common/treeitem.cpp
|
||||
../common/treemodel.cpp
|
||||
../common/utility.cpp
|
||||
../common/LZMA/LzmaDecompress.c
|
||||
../common/LZMA/SDK/C/Bra.c
|
||||
../common/LZMA/SDK/C/Bra86.c
|
||||
../common/LZMA/SDK/C/CpuArch.c
|
||||
../common/LZMA/SDK/C/LzmaDec.c
|
||||
../common/Tiano/EfiTianoDecompress.c
|
||||
../common/ustring.cpp
|
||||
../common/bstrlib/bstrlib.c
|
||||
../common/bstrlib/bstrwrap.cpp
|
||||
../common/generated/ami_nvar.cpp
|
||||
../common/generated/apple_sysf.cpp
|
||||
../common/generated/dell_dvar.cpp
|
||||
../common/generated/edk2_vss.cpp
|
||||
../common/generated/edk2_vss2.cpp
|
||||
../common/generated/edk2_ftw.cpp
|
||||
../common/generated/insyde_fdc.cpp
|
||||
../common/generated/insyde_fdm.cpp
|
||||
../common/generated/ms_slic_marker.cpp
|
||||
../common/generated/ms_slic_pubkey.cpp
|
||||
../common/generated/phoenix_flm.cpp
|
||||
../common/generated/phoenix_evsa.cpp
|
||||
../common/generated/intel_acbp_v1.cpp
|
||||
../common/generated/intel_acbp_v2.cpp
|
||||
../common/generated/intel_keym_v1.cpp
|
||||
../common/generated/intel_keym_v2.cpp
|
||||
../common/generated/intel_acm.cpp
|
||||
../common/kaitai/kaitaistream.cpp
|
||||
../common/digest/sha1.c
|
||||
../common/digest/sha256.c
|
||||
../common/digest/sha512.c
|
||||
../common/digest/sm3.c
|
||||
../common/zlib/adler32.c
|
||||
../common/zlib/compress.c
|
||||
../common/zlib/crc32.c
|
||||
../common/zlib/deflate.c
|
||||
../common/zlib/gzclose.c
|
||||
../common/zlib/gzlib.c
|
||||
../common/zlib/gzread.c
|
||||
../common/zlib/gzwrite.c
|
||||
../common/zlib/inflate.c
|
||||
../common/zlib/infback.c
|
||||
../common/zlib/inftrees.c
|
||||
../common/zlib/inffast.c
|
||||
../common/zlib/trees.c
|
||||
../common/zlib/uncompr.c
|
||||
../common/zlib/zutil.c
|
||||
)
|
||||
|
||||
ADD_DEFINITIONS(
|
||||
-DU_ENABLE_NVRAM_PARSING_SUPPORT
|
||||
-DU_ENABLE_ME_PARSING_SUPPORT
|
||||
-DU_ENABLE_FIT_PARSING_SUPPORT
|
||||
-DU_ENABLE_GUID_DATABASE_SUPPORT
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(UEFIExtract ${PROJECT_SOURCES} uefiextract.manifest)
|
||||
|
||||
IF(UNIX)
|
||||
SET_TARGET_PROPERTIES(UEFIExtract PROPERTIES OUTPUT_NAME uefiextract)
|
||||
ENDIF()
|
||||
|
||||
INSTALL(
|
||||
TARGETS UEFIExtract
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
231
UEFIExtract/ffsdumper.cpp
Normal file
|
@ -0,0 +1,231 @@
|
|||
/* ffsdumper.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#include "ffsdumper.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
USTATUS FfsDumper::dump(const UModelIndex & root, const UString & path, const DumpMode dumpMode, const UINT8 sectionType, const UString & guid)
|
||||
{
|
||||
dumped = false;
|
||||
counterHeader = counterBody = counterRaw = counterInfo = 0;
|
||||
fileList.clear();
|
||||
|
||||
if (changeDirectory(path)) {
|
||||
printf("Directory \"%s\" already exists.\n", (const char*)path.toLocal8Bit());
|
||||
return U_DIR_ALREADY_EXIST;
|
||||
}
|
||||
|
||||
currentPath = path;
|
||||
|
||||
USTATUS result = recursiveDump(root, path, dumpMode, sectionType, guid);
|
||||
if (result) {
|
||||
printf("Error %zu returned from recursiveDump (directory \"%s\").\n", result, (const char*)path.toLocal8Bit());
|
||||
return result;
|
||||
} else if (!dumped) {
|
||||
if (removeDirectory(path)) {
|
||||
printf("Removed directory \"%s\" since nothing was dumped.\n", (const char*)path.toLocal8Bit());
|
||||
}
|
||||
return U_ITEM_NOT_FOUND;
|
||||
}
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
USTATUS FfsDumper::recursiveDump(const UModelIndex & index, const UString & path, const DumpMode dumpMode, const UINT8 sectionType, const UString & guid)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
if (guid.isEmpty() ||
|
||||
(model->subtype(index) == EFI_SECTION_FREEFORM_SUBTYPE_GUID &&
|
||||
guidToUString(readUnaligned((const EFI_GUID*)(model->header(index).constData() + sizeof(EFI_COMMON_SECTION_HEADER)))) == guid) ||
|
||||
guidToUString(readUnaligned((const EFI_GUID*)model->header(index).constData())) == guid ||
|
||||
guidToUString(readUnaligned((const EFI_GUID*)model->header(model->findParentOfType(index, Types::File)).constData())) == guid) {
|
||||
|
||||
if (!changeDirectory(path) && !makeDirectory(path)) {
|
||||
printf("Cannot use directory \"%s\" (recursiveDump part 1).\n", (const char*)path.toLocal8Bit());
|
||||
return U_DIR_CREATE;
|
||||
}
|
||||
|
||||
if (currentPath != path) {
|
||||
counterHeader = counterBody = counterUncData = counterRaw = counterInfo = 0;
|
||||
currentPath = path;
|
||||
}
|
||||
|
||||
if (fileList.count(index) == 0
|
||||
&& (dumpMode == DUMP_ALL || model->rowCount(index) == 0)
|
||||
&& (sectionType == IgnoreSectionType || model->subtype(index) == sectionType)) {
|
||||
|
||||
if ((dumpMode == DUMP_ALL || dumpMode == DUMP_CURRENT || dumpMode == DUMP_HEADER)
|
||||
&& !model->hasEmptyHeader(index)) {
|
||||
fileList.insert(index);
|
||||
|
||||
UString filename;
|
||||
if (counterHeader == 0)
|
||||
filename = usprintf("%s/header.bin", path.toLocal8Bit());
|
||||
else
|
||||
filename = usprintf("%s/header_%d.bin", path.toLocal8Bit(), counterHeader);
|
||||
counterHeader++;
|
||||
|
||||
std::ofstream file(filename.toLocal8Bit(), std::ofstream::binary);
|
||||
if (!file) {
|
||||
printf("Cannot open header \"%s\".\n", (const char*)filename.toLocal8Bit());
|
||||
return U_FILE_OPEN;
|
||||
}
|
||||
|
||||
const UByteArray &data = model->header(index);
|
||||
file.write(data.constData(), data.size());
|
||||
|
||||
dumped = true;
|
||||
}
|
||||
|
||||
if ((dumpMode == DUMP_ALL || dumpMode == DUMP_CURRENT || dumpMode == DUMP_BODY)
|
||||
&& !model->hasEmptyBody(index)) {
|
||||
fileList.insert(index);
|
||||
UString filename;
|
||||
if (counterBody == 0)
|
||||
filename = usprintf("%s/body.bin", path.toLocal8Bit());
|
||||
else
|
||||
filename = usprintf("%s/body_%d.bin", path.toLocal8Bit(), counterBody);
|
||||
counterBody++;
|
||||
|
||||
std::ofstream file(filename.toLocal8Bit(), std::ofstream::binary);
|
||||
if (!file) {
|
||||
printf("Cannot open body \"%s\".\n", (const char*)filename.toLocal8Bit());
|
||||
return U_FILE_OPEN;
|
||||
}
|
||||
|
||||
const UByteArray &data = model->body(index);
|
||||
file.write(data.constData(), data.size());
|
||||
|
||||
dumped = true;
|
||||
}
|
||||
|
||||
if ((dumpMode == DUMP_ALL || dumpMode == DUMP_CURRENT || dumpMode == DUMP_UNC_DATA)
|
||||
&& !model->hasEmptyUncompressedData(index)) {
|
||||
fileList.insert(index);
|
||||
UString filename;
|
||||
if (counterUncData == 0)
|
||||
filename = usprintf("%s/unc_data.bin", path.toLocal8Bit());
|
||||
else
|
||||
filename = usprintf("%s/unc_data_%d.bin", path.toLocal8Bit(), counterUncData);
|
||||
counterUncData++;
|
||||
|
||||
std::ofstream file(filename.toLocal8Bit(), std::ofstream::binary);
|
||||
if (!file) {
|
||||
printf("Cannot open uncompressed data \"%s\".\n", (const char*)filename.toLocal8Bit());
|
||||
return U_FILE_OPEN;
|
||||
}
|
||||
|
||||
const UByteArray &data = model->uncompressedData(index);
|
||||
file.write(data.constData(), data.size());
|
||||
|
||||
dumped = true;
|
||||
}
|
||||
|
||||
if (dumpMode == DUMP_FILE) {
|
||||
UModelIndex fileIndex = index;
|
||||
if (model->type(fileIndex) != Types::File) {
|
||||
fileIndex = model->findParentOfType(index, Types::File);
|
||||
if (!fileIndex.isValid())
|
||||
fileIndex = index;
|
||||
}
|
||||
|
||||
// We may select parent file during ffs extraction.
|
||||
if (fileList.count(fileIndex) == 0) {
|
||||
fileList.insert(fileIndex);
|
||||
|
||||
UString filename;
|
||||
if (counterRaw == 0)
|
||||
filename = usprintf("%s/file.ffs", path.toLocal8Bit());
|
||||
else
|
||||
filename = usprintf("%s/file_%d.ffs", path.toLocal8Bit(), counterRaw);
|
||||
counterRaw++;
|
||||
|
||||
std::ofstream file(filename.toLocal8Bit(), std::ofstream::binary);
|
||||
if (!file) {
|
||||
printf("Cannot open file \"%s\".\n", (const char*)filename.toLocal8Bit());
|
||||
return U_FILE_OPEN;
|
||||
}
|
||||
|
||||
const UByteArray &headerData = model->header(fileIndex);
|
||||
const UByteArray &bodyData = model->body(fileIndex);
|
||||
const UByteArray &tailData = model->tail(fileIndex);
|
||||
|
||||
file.write(headerData.constData(), headerData.size());
|
||||
file.write(bodyData.constData(), bodyData.size());
|
||||
file.write(tailData.constData(), tailData.size());
|
||||
|
||||
dumped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Always dump info unless explicitly prohibited
|
||||
if ((dumpMode == DUMP_ALL || dumpMode == DUMP_CURRENT || dumpMode == DUMP_INFO)
|
||||
&& (sectionType == IgnoreSectionType || model->subtype(index) == sectionType)) {
|
||||
UString info = usprintf("Type: %s\nSubtype: %s\n%s%s\n",
|
||||
itemTypeToUString(model->type(index)).toLocal8Bit(),
|
||||
itemSubtypeToUString(model->type(index), model->subtype(index)).toLocal8Bit(),
|
||||
(model->text(index).isEmpty() ? UString("") :
|
||||
usprintf("Text: %s\n", model->text(index).toLocal8Bit())).toLocal8Bit(),
|
||||
model->info(index).toLocal8Bit());
|
||||
|
||||
UString filename;
|
||||
if (counterInfo == 0)
|
||||
filename = usprintf("%s/info.txt", path.toLocal8Bit());
|
||||
else
|
||||
filename = usprintf("%s/info_%d.txt", path.toLocal8Bit(), counterInfo);
|
||||
counterInfo++;
|
||||
|
||||
std::ofstream file(filename.toLocal8Bit());
|
||||
if (!file) {
|
||||
printf("Cannot open info \"%s\".\n", (const char*)filename.toLocal8Bit());
|
||||
return U_FILE_OPEN;
|
||||
}
|
||||
|
||||
file << info.toLocal8Bit();
|
||||
|
||||
dumped = true;
|
||||
}
|
||||
}
|
||||
|
||||
USTATUS result;
|
||||
|
||||
for (int i = 0; i < model->rowCount(index); i++) {
|
||||
UModelIndex childIndex = index.child(i, 0);
|
||||
bool useText = FALSE;
|
||||
if (model->type(childIndex) != Types::Volume)
|
||||
useText = !model->text(childIndex).isEmpty();
|
||||
|
||||
UString childPath = path;
|
||||
if (dumpMode == DUMP_ALL || dumpMode == DUMP_CURRENT) {
|
||||
if (!changeDirectory(path) && !makeDirectory(path)) {
|
||||
printf("Cannot use directory \"%s\" (recursiveDump part 2).\n", (const char*)path.toLocal8Bit());
|
||||
return U_DIR_CREATE;
|
||||
}
|
||||
|
||||
UString name = usprintf("%d %s", i, (useText ? model->text(childIndex) : model->name(childIndex)).toLocal8Bit());
|
||||
fixFileName (name, false);
|
||||
childPath = usprintf("%s/%s", path.toLocal8Bit(), name.toLocal8Bit());
|
||||
}
|
||||
result = recursiveDump(childIndex, childPath, dumpMode, sectionType, guid);
|
||||
if (result) {
|
||||
printf("Error %zu returned from recursiveDump (child directory \"%s\").\n", result, (const char*)childPath.toLocal8Bit());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
55
UEFIExtract/ffsdumper.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* ffsdumper.h
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FFSDUMPER_H
|
||||
#define FFSDUMPER_H
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "../common/basetypes.h"
|
||||
#include "../common/ustring.h"
|
||||
#include "../common/treemodel.h"
|
||||
#include "../common/ffs.h"
|
||||
#include "../common/filesystem.h"
|
||||
#include "../common/utility.h"
|
||||
|
||||
class FfsDumper
|
||||
{
|
||||
public:
|
||||
enum DumpMode {
|
||||
DUMP_CURRENT,
|
||||
DUMP_ALL,
|
||||
DUMP_BODY,
|
||||
DUMP_UNC_DATA,
|
||||
DUMP_HEADER,
|
||||
DUMP_INFO,
|
||||
DUMP_FILE
|
||||
};
|
||||
|
||||
static const UINT8 IgnoreSectionType = 0xFF;
|
||||
|
||||
explicit FfsDumper(TreeModel * treeModel) : model(treeModel), dumped(false),
|
||||
counterHeader(0), counterBody(0), counterUncData(0), counterRaw(0), counterInfo(0) {}
|
||||
~FfsDumper() {};
|
||||
|
||||
USTATUS dump(const UModelIndex & root, const UString & path, const DumpMode dumpMode = DUMP_CURRENT, const UINT8 sectionType = IgnoreSectionType, const UString & guid = UString());
|
||||
|
||||
private:
|
||||
USTATUS recursiveDump(const UModelIndex & root, const UString & path, const DumpMode dumpMode, const UINT8 sectionType, const UString & guid);
|
||||
TreeModel* model;
|
||||
UString currentPath;
|
||||
bool dumped;
|
||||
int counterHeader, counterBody, counterUncData, counterRaw, counterInfo;
|
||||
std::set<UModelIndex> fileList;
|
||||
};
|
||||
#endif // FFSDUMPER_H
|
17
UEFIExtract/meson.build
Normal file
|
@ -0,0 +1,17 @@
|
|||
executable(
|
||||
'UEFIExtract',
|
||||
sources: [
|
||||
'uefiextract_main.cpp',
|
||||
'ffsdumper.cpp',
|
||||
'uefidump.cpp',
|
||||
],
|
||||
link_with: [
|
||||
lzma,
|
||||
bstrlib,
|
||||
uefitoolcommon,
|
||||
],
|
||||
dependencies: [
|
||||
zlib,
|
||||
],
|
||||
install: true,
|
||||
)
|
151
UEFIExtract/uefidump.cpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
/* ffsdumper.cpp
|
||||
|
||||
Copyright (c) 2018, LongSoft. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#include "uefidump.h"
|
||||
#include "../common/ffs.h"
|
||||
#include "../common/utility.h"
|
||||
#include "../common/filesystem.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
USTATUS UEFIDumper::dump(const UByteArray & buffer, const UString & inPath, const UString & guid)
|
||||
{
|
||||
UString path = UString(inPath) + UString(".dump");
|
||||
UString reportPath = UString(inPath) + UString(".report.txt");
|
||||
|
||||
if (initialized) {
|
||||
// Check if called with a different buffer as before
|
||||
if (buffer != currentBuffer) {
|
||||
// Reinitalize if so
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
// Fill currentBuffer
|
||||
currentBuffer = buffer;
|
||||
|
||||
// Parse FFS structure
|
||||
USTATUS result = ffsParser.parse(buffer);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
ffsParser.outputInfo();
|
||||
|
||||
// Create ffsReport
|
||||
FfsReport ffsReport(&model);
|
||||
std::vector<UString> report = ffsReport.generate();
|
||||
if (report.size()) {
|
||||
std::ofstream ofs;
|
||||
ofs.open(reportPath, std::ofstream::out);
|
||||
for (size_t i = 0; i < report.size(); i++) {
|
||||
ofs << report[i].toLocal8Bit() << std::endl;
|
||||
}
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
// Check for dump directory existence
|
||||
if (isExistOnFs(path))
|
||||
return U_DIR_ALREADY_EXIST;
|
||||
|
||||
// Create dump directory and cd to it
|
||||
if (!makeDirectory(path))
|
||||
return U_DIR_CREATE;
|
||||
|
||||
if (!changeDirectory(path))
|
||||
return U_DIR_CHANGE;
|
||||
|
||||
dumped = false;
|
||||
USTATUS result = recursiveDump(model.index(0,0));
|
||||
if (result)
|
||||
return result;
|
||||
else if (!dumped)
|
||||
return U_ITEM_NOT_FOUND;
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
USTATUS UEFIDumper::recursiveDump(const UModelIndex & index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
// Construct file name
|
||||
UString orgName = uniqueItemName(index);
|
||||
UString name = orgName;
|
||||
bool nameFound = false;
|
||||
for (int i = 1; i < 1000; ++i) {
|
||||
if (!isExistOnFs(name + UString("_info.txt"))) {
|
||||
nameFound = true;
|
||||
break;
|
||||
}
|
||||
name = orgName + UString("_") + usprintf("%03d", i);
|
||||
}
|
||||
|
||||
if (!nameFound) {
|
||||
printf("Cannot find unique name for \"%s\".\n", (const char*)orgName.toLocal8Bit());
|
||||
return U_INVALID_PARAMETER; //TODO: replace with proper errorCode
|
||||
}
|
||||
|
||||
// Add header and body only for leaf sections
|
||||
if (model.rowCount(index) == 0) {
|
||||
// Header
|
||||
UByteArray data = model.header(index);
|
||||
if (!data.isEmpty()) {
|
||||
std::ofstream file;
|
||||
UString str = name + UString("_header.bin");
|
||||
file.open(str.toLocal8Bit(), std::ios::out | std::ios::binary);
|
||||
file.write(data.constData(), data.size());
|
||||
file.close();
|
||||
}
|
||||
|
||||
// Body
|
||||
data = model.body(index);
|
||||
if (!data.isEmpty()) {
|
||||
std::ofstream file;
|
||||
UString str = name + UString("_body.bin");
|
||||
file.open(str.toLocal8Bit(), std::ios::out | std::ios::binary);
|
||||
file.write(data.constData(), data.size());
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
// Info
|
||||
UString info = "Type: " + itemTypeToUString(model.type(index)) + "\n" +
|
||||
"Subtype: " + itemSubtypeToUString(model.type(index), model.subtype(index)) + "\n";
|
||||
if (model.text(index).length() > 0)
|
||||
info += "Text: " + model.text(index) + "\n";
|
||||
info += model.info(index) + "\n";
|
||||
|
||||
std::ofstream file;
|
||||
UString str = name + UString("_info.txt");
|
||||
file.open(str.toLocal8Bit(), std::ios::out);
|
||||
file.write(info.toLocal8Bit(), info.length());
|
||||
file.close();
|
||||
|
||||
dumped = true;
|
||||
|
||||
// Process child items
|
||||
USTATUS result;
|
||||
for (int i = 0; i < model.rowCount(index); i++) {
|
||||
result = recursiveDump(index.child(i, 0));
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
43
UEFIExtract/uefidump.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* uefidump.h
|
||||
|
||||
Copyright (c) 2018, LongSoft. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef UEFIDUMP_H
|
||||
#define UEFIDUMP_H
|
||||
|
||||
#include "../common/basetypes.h"
|
||||
#include "../common/ustring.h"
|
||||
#include "../common/treemodel.h"
|
||||
#include "../common/ffsparser.h"
|
||||
#include "../common/ffsreport.h"
|
||||
|
||||
class UEFIDumper
|
||||
{
|
||||
public:
|
||||
explicit UEFIDumper() : model(), ffsParser(&model), ffsReport(&model), currentBuffer(), initialized(false), dumped(false) {}
|
||||
~UEFIDumper() {}
|
||||
|
||||
USTATUS dump(const UByteArray & buffer, const UString & path, const UString & guid = UString());
|
||||
|
||||
private:
|
||||
USTATUS recursiveDump(const UModelIndex & root);
|
||||
|
||||
TreeModel model;
|
||||
FfsParser ffsParser;
|
||||
FfsReport ffsReport;
|
||||
|
||||
UByteArray currentBuffer;
|
||||
bool initialized;
|
||||
bool dumped;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,49 +0,0 @@
|
|||
/* uefiextract.cpp
|
||||
|
||||
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#include "uefiextract.h"
|
||||
|
||||
UEFIExtract::UEFIExtract(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
ffsEngine = new FfsEngine(this);
|
||||
}
|
||||
|
||||
UEFIExtract::~UEFIExtract()
|
||||
{
|
||||
delete ffsEngine;
|
||||
}
|
||||
|
||||
UINT8 UEFIExtract::init(const QString & path)
|
||||
{
|
||||
fileInfo = QFileInfo(path);
|
||||
|
||||
if (!fileInfo.exists())
|
||||
return ERR_FILE_OPEN;
|
||||
|
||||
QFile inputFile;
|
||||
inputFile.setFileName(path);
|
||||
|
||||
if (!inputFile.open(QFile::ReadOnly))
|
||||
return ERR_FILE_OPEN;
|
||||
|
||||
QByteArray buffer = inputFile.readAll();
|
||||
inputFile.close();
|
||||
|
||||
return ffsEngine->parseImageFile(buffer);
|
||||
}
|
||||
|
||||
UINT8 UEFIExtract::extract(QString guid)
|
||||
{
|
||||
return ffsEngine->dump(ffsEngine->treeModel()->index(0, 0), fileInfo.fileName().append(".dump"), guid);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* uefiextract.h
|
||||
|
||||
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __UEFIEXTRACT_H__
|
||||
#define __UEFIEXTRACT_H__
|
||||
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "../basetypes.h"
|
||||
#include "../ffsengine.h"
|
||||
|
||||
class UEFIExtract : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UEFIExtract(QObject *parent = 0);
|
||||
~UEFIExtract();
|
||||
|
||||
UINT8 init(const QString & path);
|
||||
UINT8 extract(QString guid = QString());
|
||||
|
||||
private:
|
||||
FfsEngine* ffsEngine;
|
||||
QFileInfo fileInfo;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
8
UEFIExtract/uefiextract.manifest
Normal file
|
@ -0,0 +1,8 @@
|
|||
<assembly xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<asmv1:assemblyIdentity type='win32' name='me.coderush.UEFIExtract' version='1.0.0.0' />
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||
<ws2:longPathAware>true</ws2:longPathAware>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
|
@ -1,43 +0,0 @@
|
|||
QT += core
|
||||
QT -= gui
|
||||
|
||||
TARGET = UEFIExtract
|
||||
TEMPLATE = app
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
DEFINES += _CONSOLE
|
||||
|
||||
SOURCES += uefiextract_main.cpp \
|
||||
uefiextract.cpp \
|
||||
../types.cpp \
|
||||
../descriptor.cpp \
|
||||
../ffs.cpp \
|
||||
../ffsengine.cpp \
|
||||
../peimage.cpp \
|
||||
../treeitem.cpp \
|
||||
../treemodel.cpp \
|
||||
../LZMA/LzmaCompress.c \
|
||||
../LZMA/LzmaDecompress.c \
|
||||
../LZMA/SDK/C/LzFind.c \
|
||||
../LZMA/SDK/C/LzmaDec.c \
|
||||
../LZMA/SDK/C/LzmaEnc.c \
|
||||
../Tiano/EfiTianoDecompress.c \
|
||||
../Tiano/EfiTianoCompress.c \
|
||||
../Tiano/EfiTianoCompressLegacy.c
|
||||
|
||||
HEADERS += uefiextract.h \
|
||||
../basetypes.h \
|
||||
../descriptor.h \
|
||||
../gbe.h \
|
||||
../me.h \
|
||||
../ffs.h \
|
||||
../peimage.h \
|
||||
../types.h \
|
||||
../ffsengine.h \
|
||||
../treeitem.h \
|
||||
../treemodel.h \
|
||||
../LZMA/LzmaCompress.h \
|
||||
../LZMA/LzmaDecompress.h \
|
||||
../Tiano/EfiTianoDecompress.h \
|
||||
../Tiano/EfiTianoCompress.h
|
||||
|
|
@ -1,60 +1,219 @@
|
|||
/* uefiextract_main.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2018, LongSoft. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include <iostream>
|
||||
#include "uefiextract.h"
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "../version.h"
|
||||
#include "../common/basetypes.h"
|
||||
#include "../common/ustring.h"
|
||||
#include "../common/filesystem.h"
|
||||
#include "../common/ffsparser.h"
|
||||
#include "../common/ffsreport.h"
|
||||
#include "../common/guiddatabase.h"
|
||||
#include "ffsdumper.h"
|
||||
#include "uefidump.h"
|
||||
|
||||
enum ReadType {
|
||||
READ_INPUT,
|
||||
READ_OUTPUT,
|
||||
READ_MODE,
|
||||
READ_SECTION
|
||||
};
|
||||
|
||||
void print_usage()
|
||||
{
|
||||
std::cout << "UEFIExtract " PROGRAM_VERSION << std::endl
|
||||
<< "Usage: UEFIExtract {-h | --help | -v | --version} - show help and/or version information." << std::endl
|
||||
<< " UEFIExtract imagefile - generate report and GUID database, then dump only leaf tree items into .dump folder." << std::endl
|
||||
<< " UEFIExtract imagefile all - generate report and GUID database, then dump all tree items into .dump folder." << std::endl
|
||||
<< " UEFIExtract imagefile unpack - generate report, then dump all tree items into a single .dump folder (legacy UEFIDump compatibility mode)." << std::endl
|
||||
<< " UEFIExtract imagefile dump - only generate dump, no report or GUID database needed." << std::endl
|
||||
<< " UEFIExtract imagefile report - only generate report, no dump or GUID database needed." << std::endl
|
||||
<< " UEFIExtract imagefile guids - only generate GUID database, no dump or report needed." << std::endl
|
||||
<< " UEFIExtract imagefile GUID_1 ... [ -o FILE_1 ... ] [ -m MODE_1 ... ] [ -t TYPE_1 ... ] -" << std::endl
|
||||
<< " Dump only FFS file(s) with specific GUID(s), without report or GUID database." << std::endl
|
||||
<< " Type is section type or FF to ignore. Mode is one of: all, body, unc_data, header, info, file." << std::endl
|
||||
<< " Return value is a bit mask where 0 at position N means that file with GUID_N was found and unpacked, 1 otherwise." << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
a.setOrganizationName("CodeRush");
|
||||
a.setOrganizationDomain("coderush.me");
|
||||
a.setApplicationName("UEFIExtract");
|
||||
initGuidDatabase("guids.csv");
|
||||
|
||||
UEFIExtract w;
|
||||
UINT8 result = ERR_SUCCESS;
|
||||
UINT32 returned = 0;
|
||||
|
||||
if (a.arguments().length() > 32) {
|
||||
std::cout << "Too many arguments" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a.arguments().length() > 1 ) {
|
||||
if (w.init(a.arguments().at(1)))
|
||||
return 1;
|
||||
|
||||
if (a.arguments().length() == 2) {
|
||||
result = w.extract();
|
||||
if (result)
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
for (int i = 2; i < a.arguments().length(); i++) {
|
||||
result = w.extract(a.arguments().at(i));
|
||||
if (result)
|
||||
returned |= (1 << (i - 1));
|
||||
}
|
||||
return returned;
|
||||
if (argc <= 1) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
std::cout << "UEFIExtract 0.4.4" << std::endl << std::endl <<
|
||||
"Usage: uefiextract imagefile [FileGUID_1 FileGUID_2 ... FileGUID_31]" << std::endl <<
|
||||
"Returned value is a bit mask where 0 on position N meant File with GUID_N was found and unpacked, 1 otherwise" << std::endl;
|
||||
// Help and version
|
||||
if (argc == 2) {
|
||||
UString arg = UString(argv[1]);
|
||||
if (arg == UString("-h") || arg == UString("--help")) {
|
||||
print_usage();
|
||||
return 0;
|
||||
}
|
||||
else if (arg == UString("-v") || arg == UString("--version")) {
|
||||
std::cout << PROGRAM_VERSION << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that input file exists
|
||||
USTATUS result;
|
||||
UByteArray buffer;
|
||||
UString path = getAbsPath(argv[1]);
|
||||
if (false == readFileIntoBuffer(path, buffer))
|
||||
return U_FILE_OPEN;
|
||||
|
||||
// Hack to support legacy UEFIDump mode
|
||||
if (argc == 3 && !std::strcmp(argv[2], "unpack")) {
|
||||
UEFIDumper uefidumper;
|
||||
return (uefidumper.dump(buffer, UString(argv[1])) != U_SUCCESS);
|
||||
}
|
||||
|
||||
// Create model and ffsParser
|
||||
TreeModel model;
|
||||
FfsParser ffsParser(&model);
|
||||
// Parse input buffer
|
||||
result = ffsParser.parse(buffer);
|
||||
if (result)
|
||||
return (int)result;
|
||||
|
||||
ffsParser.outputInfo();
|
||||
|
||||
// Create ffsDumper
|
||||
FfsDumper ffsDumper(&model);
|
||||
|
||||
// Dump only leaf elements, no report or GUID database
|
||||
if (argc == 3 && !std::strcmp(argv[2], "dump")) {
|
||||
return (ffsDumper.dump(model.index(0, 0), path + UString(".dump")) != U_SUCCESS);
|
||||
}
|
||||
// Dump named GUIDs found in the image, no dump or report
|
||||
else if (argc == 3 && !std::strcmp(argv[2], "guids")) {
|
||||
GuidDatabase db = guidDatabaseFromTreeRecursive(&model, model.index(0, 0));
|
||||
if (!db.empty()) {
|
||||
return (int)guidDatabaseExportToFile(path + UString(".guids.csv"), db);
|
||||
}
|
||||
}
|
||||
// Generate report, no dump or GUID database
|
||||
else if (argc == 3 && !std::strcmp(argv[2], "report")) {
|
||||
FfsReport ffsReport(&model);
|
||||
std::vector<UString> report = ffsReport.generate();
|
||||
if (report.size()) {
|
||||
std::ofstream file;
|
||||
file.open((path + UString(".report.txt")).toLocal8Bit());
|
||||
for (size_t i = 0; i < report.size(); i++)
|
||||
file << report[i].toLocal8Bit() << '\n';
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// Either default or all mode
|
||||
else if (argc == 2 || (argc == 3 && !std::strcmp(argv[2], "all"))) {
|
||||
// Generate report
|
||||
FfsReport ffsReport(&model);
|
||||
std::vector<UString> report = ffsReport.generate();
|
||||
if (report.size()) {
|
||||
std::ofstream file;
|
||||
file.open((path + UString(".report.txt")).toLocal8Bit());
|
||||
for (size_t i = 0; i < report.size(); i++)
|
||||
file << report[i].toLocal8Bit() << '\n';
|
||||
}
|
||||
|
||||
// Create GUID database
|
||||
GuidDatabase db = guidDatabaseFromTreeRecursive(&model, model.index(0, 0));
|
||||
if (!db.empty()) {
|
||||
guidDatabaseExportToFile(path + UString(".guids.csv"), db);
|
||||
}
|
||||
|
||||
// Dump all non-leaf elements, with report and GUID database, default
|
||||
if (argc == 2) {
|
||||
return (ffsDumper.dump(model.index(0, 0), path + UString(".dump")) != U_SUCCESS);
|
||||
}
|
||||
else if (argc == 3 && !std::strcmp(argv[2], "all")) { // Dump every element with report and GUID database
|
||||
return (ffsDumper.dump(model.index(0, 0), path + UString(".dump"), FfsDumper::DUMP_ALL) != U_SUCCESS);
|
||||
}
|
||||
}
|
||||
// Dump specific files, without report or GUID database
|
||||
else {
|
||||
std::vector<UString> inputs, outputs;
|
||||
std::vector<FfsDumper::DumpMode> modes;
|
||||
std::vector<UINT8> sectionTypes;
|
||||
ReadType readType = READ_INPUT;
|
||||
for (int i = 2; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!std::strcmp(arg, "-i")) {
|
||||
readType = READ_INPUT;
|
||||
continue;
|
||||
} else if (!std::strcmp(arg, "-o")) {
|
||||
readType = READ_OUTPUT;
|
||||
continue;
|
||||
} else if (!std::strcmp(arg, "-m")) {
|
||||
readType = READ_MODE;
|
||||
continue;
|
||||
} else if (!std::strcmp(arg, "-t")) {
|
||||
readType = READ_SECTION;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (readType == READ_INPUT) {
|
||||
inputs.push_back(arg);
|
||||
} else if (readType == READ_OUTPUT) {
|
||||
outputs.push_back(getAbsPath(arg));
|
||||
} else if (readType == READ_MODE) {
|
||||
if (!std::strcmp(arg, "all"))
|
||||
modes.push_back(FfsDumper::DUMP_ALL);
|
||||
else if (!std::strcmp(arg, "body"))
|
||||
modes.push_back(FfsDumper::DUMP_BODY);
|
||||
else if (!std::strcmp(arg, "unc_data"))
|
||||
modes.push_back(FfsDumper::DUMP_UNC_DATA);
|
||||
else if (!std::strcmp(arg, "header"))
|
||||
modes.push_back(FfsDumper::DUMP_HEADER);
|
||||
else if (!std::strcmp(arg, "info"))
|
||||
modes.push_back(FfsDumper::DUMP_INFO);
|
||||
else if (!std::strcmp(arg, "file"))
|
||||
modes.push_back(FfsDumper::DUMP_FILE);
|
||||
else
|
||||
return U_INVALID_PARAMETER;
|
||||
} else if (readType == READ_SECTION) {
|
||||
char *converted = const_cast<char *>(arg);
|
||||
UINT8 sectionType = (UINT8)std::strtol(arg, &converted, 16);
|
||||
if (converted == arg)
|
||||
return U_INVALID_PARAMETER;
|
||||
sectionTypes.push_back(sectionType);
|
||||
}
|
||||
}
|
||||
if (inputs.empty() || (!outputs.empty() && inputs.size() != outputs.size()) ||
|
||||
(!modes.empty() && inputs.size() != modes.size()) ||
|
||||
(!sectionTypes.empty() && inputs.size() != sectionTypes.size()))
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
USTATUS lastError = U_SUCCESS;
|
||||
for (size_t i = 0; i < inputs.size(); i++) {
|
||||
UString outPath = outputs.empty() ? path + UString(".dump") : outputs[i];
|
||||
FfsDumper::DumpMode mode = modes.empty() ? FfsDumper::DUMP_ALL : modes[i];
|
||||
UINT8 type = sectionTypes.empty() ? FfsDumper::IgnoreSectionType : sectionTypes[i];
|
||||
result = ffsDumper.dump(model.index(0, 0), outPath, mode, type, inputs[i]);
|
||||
if (result) {
|
||||
std::cout << "Guid " << inputs[i].toLocal8Bit() << " failed with " << result << " code!" << std::endl;
|
||||
lastError = result;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)lastError;
|
||||
}
|
||||
|
||||
// If parameters are different, show version and usage information
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
82
UEFIFind/CMakeLists.txt
Normal file
|
@ -0,0 +1,82 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 3.22)
|
||||
|
||||
PROJECT(UEFIFind)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
SET(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
SET(PROJECT_SOURCES
|
||||
uefifind_main.cpp
|
||||
uefifind.cpp
|
||||
../common/guiddatabase.cpp
|
||||
../common/types.cpp
|
||||
../common/filesystem.cpp
|
||||
../common/descriptor.cpp
|
||||
../common/ffs.cpp
|
||||
../common/nvram.cpp
|
||||
../common/nvramparser.cpp
|
||||
../common/ffsparser.cpp
|
||||
../common/fitparser.cpp
|
||||
../common/peimage.cpp
|
||||
../common/treeitem.cpp
|
||||
../common/treemodel.cpp
|
||||
../common/utility.cpp
|
||||
../common/LZMA/LzmaDecompress.c
|
||||
../common/LZMA/SDK/C/Bra.c
|
||||
../common/LZMA/SDK/C/Bra86.c
|
||||
../common/LZMA/SDK/C/CpuArch.c
|
||||
../common/LZMA/SDK/C/LzmaDec.c
|
||||
../common/Tiano/EfiTianoDecompress.c
|
||||
../common/ustring.cpp
|
||||
../common/bstrlib/bstrlib.c
|
||||
../common/bstrlib/bstrwrap.cpp
|
||||
../common/generated/ami_nvar.cpp
|
||||
../common/generated/apple_sysf.cpp
|
||||
../common/generated/dell_dvar.cpp
|
||||
../common/generated/edk2_vss.cpp
|
||||
../common/generated/edk2_vss2.cpp
|
||||
../common/generated/edk2_ftw.cpp
|
||||
../common/generated/insyde_fdc.cpp
|
||||
../common/generated/insyde_fdm.cpp
|
||||
../common/generated/ms_slic_marker.cpp
|
||||
../common/generated/ms_slic_pubkey.cpp
|
||||
../common/generated/phoenix_flm.cpp
|
||||
../common/generated/phoenix_evsa.cpp
|
||||
../common/generated/intel_acbp_v1.cpp
|
||||
../common/generated/intel_acbp_v2.cpp
|
||||
../common/generated/intel_keym_v1.cpp
|
||||
../common/generated/intel_keym_v2.cpp
|
||||
../common/generated/intel_acm.cpp
|
||||
../common/kaitai/kaitaistream.cpp
|
||||
../common/digest/sha1.c
|
||||
../common/digest/sha256.c
|
||||
../common/digest/sha512.c
|
||||
../common/digest/sm3.c
|
||||
../common/zlib/adler32.c
|
||||
../common/zlib/compress.c
|
||||
../common/zlib/crc32.c
|
||||
../common/zlib/deflate.c
|
||||
../common/zlib/gzclose.c
|
||||
../common/zlib/gzlib.c
|
||||
../common/zlib/gzread.c
|
||||
../common/zlib/gzwrite.c
|
||||
../common/zlib/inflate.c
|
||||
../common/zlib/infback.c
|
||||
../common/zlib/inftrees.c
|
||||
../common/zlib/inffast.c
|
||||
../common/zlib/trees.c
|
||||
../common/zlib/uncompr.c
|
||||
../common/zlib/zutil.c
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(UEFIFind ${PROJECT_SOURCES} uefifind.manifest)
|
||||
|
||||
IF(UNIX)
|
||||
SET_TARGET_PROPERTIES(UEFIFind PROPERTIES OUTPUT_NAME uefifind)
|
||||
ENDIF()
|
||||
|
||||
INSTALL(
|
||||
TARGETS UEFIFind
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
16
UEFIFind/meson.build
Normal file
|
@ -0,0 +1,16 @@
|
|||
executable(
|
||||
'UEFIFind',
|
||||
sources: [
|
||||
'uefifind_main.cpp',
|
||||
'uefifind.cpp',
|
||||
],
|
||||
link_with: [
|
||||
lzma,
|
||||
bstrlib,
|
||||
uefitoolcommon,
|
||||
],
|
||||
dependencies: [
|
||||
zlib,
|
||||
],
|
||||
install: true,
|
||||
)
|
|
@ -1,6 +1,6 @@
|
|||
/* uefifind.cpp
|
||||
|
||||
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
|
@ -12,149 +12,137 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
*/
|
||||
|
||||
#include "uefifind.h"
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
||||
UEFIFind::UEFIFind(QObject *parent) :
|
||||
QObject(parent)
|
||||
|
||||
UEFIFind::UEFIFind()
|
||||
{
|
||||
ffsEngine = new FfsEngine(this);
|
||||
model = ffsEngine->treeModel();
|
||||
model = new TreeModel();
|
||||
ffsParser = new FfsParser(model);
|
||||
initDone = false;
|
||||
}
|
||||
|
||||
UEFIFind::~UEFIFind()
|
||||
{
|
||||
delete ffsParser;
|
||||
delete model;
|
||||
model = NULL;
|
||||
delete ffsEngine;
|
||||
}
|
||||
|
||||
UINT8 UEFIFind::init(const QString & path)
|
||||
USTATUS UEFIFind::init(const UString & path)
|
||||
{
|
||||
UINT8 result;
|
||||
|
||||
fileInfo = QFileInfo(path);
|
||||
UByteArray buffer;
|
||||
if (false == readFileIntoBuffer(path, buffer))
|
||||
return U_FILE_OPEN;
|
||||
|
||||
if (!fileInfo.exists())
|
||||
return ERR_FILE_OPEN;
|
||||
|
||||
QFile inputFile;
|
||||
inputFile.setFileName(path);
|
||||
|
||||
if (!inputFile.open(QFile::ReadOnly))
|
||||
return ERR_FILE_OPEN;
|
||||
|
||||
QByteArray buffer = inputFile.readAll();
|
||||
inputFile.close();
|
||||
|
||||
result = ffsEngine->parseImageFile(buffer);
|
||||
USTATUS result = ffsParser->parse(buffer);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
initDone = true;
|
||||
return ERR_SUCCESS;
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
QString UEFIFind::guidToQString(const UINT8* guid)
|
||||
USTATUS UEFIFind::findFileRecursive(const UModelIndex index, const UString & hexPattern, const UINT8 mode, std::set<std::pair<UModelIndex, UModelIndex> > & files)
|
||||
{
|
||||
const UINT32 u32 = *(const UINT32*)guid;
|
||||
const UINT16 u16_1 = *(const UINT16*)(guid + 4);
|
||||
const UINT16 u16_2 = *(const UINT16*)(guid + 6);
|
||||
const UINT8 u8_1 = *(const UINT8*)(guid + 8);
|
||||
const UINT8 u8_2 = *(const UINT8*)(guid + 9);
|
||||
const UINT8 u8_3 = *(const UINT8*)(guid + 10);
|
||||
const UINT8 u8_4 = *(const UINT8*)(guid + 11);
|
||||
const UINT8 u8_5 = *(const UINT8*)(guid + 12);
|
||||
const UINT8 u8_6 = *(const UINT8*)(guid + 13);
|
||||
const UINT8 u8_7 = *(const UINT8*)(guid + 14);
|
||||
const UINT8 u8_8 = *(const UINT8*)(guid + 15);
|
||||
if (!index.isValid())
|
||||
return U_SUCCESS;
|
||||
|
||||
return QString("%1-%2-%3-%4%5-%6%7%8%9%10%11").hexarg2(u32, 8).hexarg2(u16_1, 4).hexarg2(u16_2, 4).hexarg2(u8_1, 2).hexarg2(u8_2, 2)
|
||||
.hexarg2(u8_3, 2).hexarg2(u8_4, 2).hexarg2(u8_5, 2).hexarg2(u8_6, 2).hexarg2(u8_7, 2).hexarg2(u8_8, 2);
|
||||
if (hexPattern.isEmpty())
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
const char *hexPatternRaw = hexPattern.toLocal8Bit();
|
||||
std::vector<UINT8> pattern, patternMask;
|
||||
if (!makePattern(hexPatternRaw, pattern, patternMask))
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
// Check for "all substrings" pattern
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < patternMask.size(); i++)
|
||||
if (patternMask[i] == 0)
|
||||
count++;
|
||||
if (count == patternMask.size())
|
||||
return U_SUCCESS;
|
||||
|
||||
bool hasChildren = (model->rowCount(index) > 0);
|
||||
for (int i = 0; i < model->rowCount(index); i++) {
|
||||
findFileRecursive(index.model()->index(i, index.column(), index), hexPattern, mode, files);
|
||||
}
|
||||
|
||||
// TODO: handle a case where an item has both compressed and uncompressed bodies
|
||||
UByteArray data;
|
||||
if (hasChildren) {
|
||||
if (mode == SEARCH_MODE_HEADER)
|
||||
data = model->header(index);
|
||||
else if (mode == SEARCH_MODE_ALL)
|
||||
data = model->header(index) + model->body(index);
|
||||
}
|
||||
else {
|
||||
if (mode == SEARCH_MODE_HEADER)
|
||||
data = model->header(index);
|
||||
else if (mode == SEARCH_MODE_BODY)
|
||||
data = model->body(index);
|
||||
else
|
||||
data = model->header(index) + model->body(index);
|
||||
}
|
||||
|
||||
const UINT8 *rawData = reinterpret_cast<const UINT8 *>(data.constData());
|
||||
INTN offset = findPattern(pattern.data(), patternMask.data(), pattern.size(), rawData, data.size(), 0);
|
||||
|
||||
// For patterns that cross header|body boundary, skip patterns entirely located in body, since
|
||||
// children search above has already found them.
|
||||
if (hasChildren && mode == SEARCH_MODE_ALL && offset >= model->header(index).size()) {
|
||||
offset = -1;
|
||||
}
|
||||
|
||||
if (offset >= 0) {
|
||||
if (model->type(index) != Types::File) {
|
||||
UModelIndex parentFile = model->findParentOfType(index, Types::File);
|
||||
if (model->type(index) == Types::Section && model->subtype(index) == EFI_SECTION_FREEFORM_SUBTYPE_GUID)
|
||||
files.insert(std::pair<UModelIndex, UModelIndex>(parentFile, index));
|
||||
else
|
||||
files.insert(std::pair<UModelIndex, UModelIndex>(parentFile, UModelIndex()));
|
||||
}
|
||||
else {
|
||||
files.insert(std::pair<UModelIndex, UModelIndex>(index, UModelIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
UINT8 UEFIFind::find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result)
|
||||
USTATUS UEFIFind::find(const UINT8 mode, const bool count, const UString & hexPattern, UString & result)
|
||||
{
|
||||
QModelIndex root = model->index(0, 0);
|
||||
QSet<QPair<QModelIndex, QModelIndex> > files;
|
||||
UModelIndex root = model->index(0, 0);
|
||||
std::set<std::pair<UModelIndex, UModelIndex> > files;
|
||||
|
||||
result.clear();
|
||||
|
||||
UINT8 returned = findFileRecursive(root, hexPattern, mode, files);
|
||||
USTATUS returned = findFileRecursive(root, hexPattern, mode, files);
|
||||
if (returned)
|
||||
return returned;
|
||||
|
||||
if (count) {
|
||||
if (files.count())
|
||||
result.append(QString("%1\n").arg(files.count()));
|
||||
return ERR_SUCCESS;
|
||||
if (!files.empty())
|
||||
result += usprintf("%lu\n", files.size());
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
QPair<QModelIndex, QModelIndex> indexes;
|
||||
Q_FOREACH(indexes, files) {
|
||||
QByteArray data = model->header(indexes.first).left(16);
|
||||
result.append(guidToQString((const UINT8*)data.constData()));
|
||||
for (std::set<std::pair<UModelIndex, UModelIndex> >::const_iterator citer = files.begin(); citer != files.end(); ++citer) {
|
||||
UByteArray data(16, '\x00');
|
||||
std::pair<UModelIndex, UModelIndex> indexes = *citer;
|
||||
if (!model->hasEmptyHeader(indexes.first))
|
||||
data = model->header(indexes.first).left(16);
|
||||
result += guidToUString(readUnaligned((const EFI_GUID*)data.constData()));
|
||||
|
||||
// Special case of freeform subtype GUID files
|
||||
if (indexes.second.isValid() && model->subtype(indexes.second) == EFI_SECTION_FREEFORM_SUBTYPE_GUID) {
|
||||
data = model->header(indexes.second).left(sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION));
|
||||
result.append(" ").append(guidToQString((const UINT8*)data.constData() + sizeof(EFI_COMMON_SECTION_HEADER)));
|
||||
data = model->header(indexes.second);
|
||||
result += UString(" ") + (guidToUString(readUnaligned((const EFI_GUID*)(data.constData() + sizeof(EFI_COMMON_SECTION_HEADER)))));
|
||||
}
|
||||
|
||||
result.append("\n");
|
||||
|
||||
result += UString("\n");
|
||||
}
|
||||
return ERR_SUCCESS;
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
UINT8 UEFIFind::findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet<QPair<QModelIndex, QModelIndex> > & files)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return ERR_SUCCESS;
|
||||
|
||||
if (hexPattern.isEmpty())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
|
||||
// Check for "all substrings" pattern
|
||||
if (hexPattern.count('.') == hexPattern.length())
|
||||
return ERR_SUCCESS;
|
||||
|
||||
bool hasChildren = (model->rowCount(index) > 0);
|
||||
for (int i = 0; i < model->rowCount(index); i++) {
|
||||
findFileRecursive(index.child(i, index.column()), hexPattern, mode, files);
|
||||
}
|
||||
|
||||
QByteArray data;
|
||||
if (hasChildren) {
|
||||
if (mode == SEARCH_MODE_HEADER || mode == SEARCH_MODE_ALL)
|
||||
data.append(model->header(index));
|
||||
}
|
||||
else {
|
||||
if (mode == SEARCH_MODE_HEADER)
|
||||
data.append(model->header(index));
|
||||
else if (mode == SEARCH_MODE_BODY)
|
||||
data.append(model->body(index));
|
||||
else
|
||||
data.append(model->header(index)).append(model->body(index));
|
||||
}
|
||||
|
||||
QString hexBody = QString(data.toHex());
|
||||
QRegExp regexp = QRegExp(QString(hexPattern), Qt::CaseInsensitive);
|
||||
INT32 offset = regexp.indexIn(hexBody);
|
||||
while (offset >= 0) {
|
||||
if (offset % 2 == 0) {
|
||||
if (model->type(index) != Types::File) {
|
||||
QModelIndex ffs = model->findParentOfType(index, Types::File);
|
||||
if (model->type(index) == Types::Section && model->subtype(index) == EFI_SECTION_FREEFORM_SUBTYPE_GUID)
|
||||
files.insert(QPair<QModelIndex, QModelIndex>(ffs, index));
|
||||
else
|
||||
files.insert(QPair<QModelIndex, QModelIndex>(ffs, QModelIndex()));
|
||||
}
|
||||
else
|
||||
files.insert(QPair<QModelIndex, QModelIndex>(index, QModelIndex()));
|
||||
|
||||
break;
|
||||
}
|
||||
offset = regexp.indexIn(hexBody, offset + 1);
|
||||
}
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/* uefifind.h
|
||||
|
||||
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
|
@ -11,42 +11,34 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
|
||||
*/
|
||||
|
||||
#ifndef __UEFIFIND_H__
|
||||
#define __UEFIFIND_H__
|
||||
#ifndef UEFIFIND_H
|
||||
#define UEFIFIND_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QPair>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QUuid>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
|
||||
#include "../basetypes.h"
|
||||
#include "../ffsengine.h"
|
||||
#include "../ffs.h"
|
||||
#include "../common/basetypes.h"
|
||||
#include "../common/ustring.h"
|
||||
#include "../common/filesystem.h"
|
||||
#include "../common/ffsparser.h"
|
||||
#include "../common/ffs.h"
|
||||
#include "../common/utility.h"
|
||||
|
||||
class UEFIFind : public QObject
|
||||
class UEFIFind
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UEFIFind(QObject *parent = 0);
|
||||
explicit UEFIFind();
|
||||
~UEFIFind();
|
||||
|
||||
UINT8 init(const QString & path);
|
||||
UINT8 find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result);
|
||||
USTATUS init(const UString & path);
|
||||
USTATUS find(const UINT8 mode, const bool count, const UString & hexPattern, UString & result);
|
||||
|
||||
private:
|
||||
UINT8 findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet<QPair<QModelIndex, QModelIndex> > & files);
|
||||
QString guidToQString(const UINT8* guid);
|
||||
USTATUS findFileRecursive(const UModelIndex index, const UString & hexPattern, const UINT8 mode, std::set<std::pair<UModelIndex, UModelIndex> > & files);
|
||||
|
||||
FfsEngine* ffsEngine;
|
||||
FfsParser* ffsParser;
|
||||
TreeModel* model;
|
||||
QFileInfo fileInfo;
|
||||
bool initDone;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // UEFIFIND_H
|
||||
|
|
8
UEFIFind/uefifind.manifest
Normal file
|
@ -0,0 +1,8 @@
|
|||
<assembly xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<asmv1:assemblyIdentity type='win32' name='me.coderush.UEFIFind' version='1.0.0.0' />
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||
<ws2:longPathAware>true</ws2:longPathAware>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
|
@ -1,43 +0,0 @@
|
|||
QT += core
|
||||
QT -= gui
|
||||
|
||||
TARGET = UEFIFind
|
||||
TEMPLATE = app
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
DEFINES += _CONSOLE _DISABLE_ENGINE_MESSAGES
|
||||
|
||||
SOURCES += uefifind_main.cpp \
|
||||
uefifind.cpp \
|
||||
../types.cpp \
|
||||
../descriptor.cpp \
|
||||
../ffs.cpp \
|
||||
../ffsengine.cpp \
|
||||
../peimage.cpp \
|
||||
../treeitem.cpp \
|
||||
../treemodel.cpp \
|
||||
../LZMA/LzmaCompress.c \
|
||||
../LZMA/LzmaDecompress.c \
|
||||
../LZMA/SDK/C/LzFind.c \
|
||||
../LZMA/SDK/C/LzmaDec.c \
|
||||
../LZMA/SDK/C/LzmaEnc.c \
|
||||
../Tiano/EfiTianoDecompress.c \
|
||||
../Tiano/EfiTianoCompress.c \
|
||||
../Tiano/EfiTianoCompressLegacy.c
|
||||
|
||||
HEADERS += uefifind.h \
|
||||
../basetypes.h \
|
||||
../descriptor.h \
|
||||
../gbe.h \
|
||||
../me.h \
|
||||
../ffs.h \
|
||||
../peimage.h \
|
||||
../types.h \
|
||||
../ffsengine.h \
|
||||
../treeitem.h \
|
||||
../treemodel.h \
|
||||
../LZMA/LzmaCompress.h \
|
||||
../LZMA/LzmaDecompress.h \
|
||||
../Tiano/EfiTianoDecompress.h \
|
||||
../Tiano/EfiTianoCompress.h
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/* uefifind_main.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2018, LongSoft. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
|
@ -10,63 +10,183 @@ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
#include <QCoreApplication>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../version.h"
|
||||
#include "../common/guiddatabase.h"
|
||||
#include "uefifind.h"
|
||||
|
||||
void print_usage()
|
||||
{
|
||||
std::cout << "UEFIFind " PROGRAM_VERSION << std::endl <<
|
||||
"Usage: UEFIFind {-h | --help | -v | -version}" << std::endl <<
|
||||
" UEFIFind imagefile {header | body | all} {list | count} pattern" << std::endl <<
|
||||
" UEFIFind imagefile file patternsfile" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
a.setOrganizationName("CodeRush");
|
||||
a.setOrganizationDomain("coderush.me");
|
||||
a.setApplicationName("UEFIFind");
|
||||
|
||||
UEFIFind w;
|
||||
UINT8 result;
|
||||
USTATUS result;
|
||||
|
||||
if (a.arguments().length() == 5) {
|
||||
result = w.init(a.arguments().at(4));
|
||||
if (result)
|
||||
return result;
|
||||
if (argc == 1) {
|
||||
print_usage();
|
||||
return U_SUCCESS;
|
||||
}
|
||||
else if (argc == 2) {
|
||||
UString arg = argv[1];
|
||||
if (arg == UString("-h") || arg == UString("--help")) {
|
||||
print_usage();
|
||||
return U_SUCCESS;
|
||||
}
|
||||
else if (arg == UString("-v") || arg == UString("--version")) {
|
||||
std::cout << PROGRAM_VERSION << std::endl;
|
||||
return U_SUCCESS;
|
||||
}
|
||||
}
|
||||
else if (argc == 5) {
|
||||
UString inputArg = argv[1];
|
||||
UString modeArg = argv[2];
|
||||
UString subModeArg = argv[3];
|
||||
UString patternArg = argv[4];
|
||||
|
||||
// Get search mode
|
||||
UINT8 mode;
|
||||
if (a.arguments().at(1) == QString("header"))
|
||||
if (modeArg == UString("header"))
|
||||
mode = SEARCH_MODE_HEADER;
|
||||
else if (a.arguments().at(1) == QString("body"))
|
||||
else if (modeArg == UString("body"))
|
||||
mode = SEARCH_MODE_BODY;
|
||||
else if (a.arguments().at(1) == QString("all"))
|
||||
else if (modeArg == UString("all"))
|
||||
mode = SEARCH_MODE_ALL;
|
||||
else
|
||||
return ERR_INVALID_PARAMETER;
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
// Get result type
|
||||
bool count;
|
||||
if (a.arguments().at(2) == QString("list"))
|
||||
if (subModeArg == UString("list"))
|
||||
count = false;
|
||||
else if (a.arguments().at(2) == QString("count"))
|
||||
else if (subModeArg == UString("count"))
|
||||
count = true;
|
||||
else
|
||||
return ERR_INVALID_PARAMETER;
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
// Go find the supplied pattern
|
||||
QString found;
|
||||
result = w.find(mode, count, a.arguments().at(3), found);
|
||||
// Parse input file
|
||||
result = w.init(inputArg);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
// Nothing was found
|
||||
// Go find the supplied pattern
|
||||
UString found;
|
||||
result = w.find(mode, count, patternArg, found);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
// Nothing is found
|
||||
if (found.isEmpty())
|
||||
return ERR_ITEM_NOT_FOUND;
|
||||
return U_ITEM_NOT_FOUND;
|
||||
|
||||
// Print result
|
||||
std::cout << found.toStdString();
|
||||
return ERR_SUCCESS;
|
||||
std::cout << found.toLocal8Bit();
|
||||
return U_SUCCESS;
|
||||
}
|
||||
else {
|
||||
std::cout << "UEFIFind 0.3.4" << std::endl << std::endl <<
|
||||
"Usage: uefifind {header | body | all} {list | count} pattern imagefile\n";
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
else if (argc == 4) {
|
||||
UString inputArg = argv[1];
|
||||
UString modeArg = argv[2];
|
||||
UString patternArg = argv[3];
|
||||
|
||||
// Get search mode
|
||||
if (modeArg != UString("file"))
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
// Open patterns file
|
||||
if (!isExistOnFs(patternArg))
|
||||
return U_FILE_OPEN;
|
||||
|
||||
std::ifstream patternsFile(patternArg.toLocal8Bit());
|
||||
if (!patternsFile)
|
||||
return U_FILE_OPEN;
|
||||
|
||||
// Parse input file
|
||||
result = w.init(inputArg);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
// Perform searches
|
||||
bool somethingFound = false;
|
||||
while (!patternsFile.eof()) {
|
||||
std::string line;
|
||||
std::getline(patternsFile, line);
|
||||
// Use sharp symbol as commentary
|
||||
if (line.size() == 0 || line[0] == '#')
|
||||
continue;
|
||||
|
||||
// Split the read line
|
||||
std::vector<UString> list;
|
||||
std::string::size_type prev = 0, curr = 0;
|
||||
while ((curr = line.find(' ', curr)) != std::string::npos) {
|
||||
std::string substring( line.substr(prev, curr-prev) );
|
||||
list.push_back(UString(substring.c_str()));
|
||||
prev = ++curr;
|
||||
}
|
||||
list.push_back(UString(line.substr(prev, curr-prev).c_str()));
|
||||
|
||||
if (list.size() < 3) {
|
||||
std::cout << line << std::endl << "skipped, too few arguments" << std::endl << std::endl;
|
||||
continue;
|
||||
}
|
||||
// Get search mode
|
||||
UINT8 mode;
|
||||
if (list.at(0) == UString("header"))
|
||||
mode = SEARCH_MODE_HEADER;
|
||||
else if (list.at(0) == UString("body"))
|
||||
mode = SEARCH_MODE_BODY;
|
||||
else if (list.at(0) == UString("all"))
|
||||
mode = SEARCH_MODE_ALL;
|
||||
else {
|
||||
std::cout << line << std::endl << "skipped, invalid search mode" << std::endl << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get result type
|
||||
bool count;
|
||||
if (list.at(1) == UString("list"))
|
||||
count = false;
|
||||
else if (list.at(1) == UString("count"))
|
||||
count = true;
|
||||
else {
|
||||
std::cout << line << std::endl << "skipped, invalid result type" << std::endl << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Go find the supplied pattern
|
||||
UString found;
|
||||
result = w.find(mode, count, list.at(2), found);
|
||||
if (result) {
|
||||
std::cout << line << std::endl << "skipped, find failed with error " << (UINT32)result << std::endl << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (found.isEmpty()) {
|
||||
// Nothing is found
|
||||
std::cout << line << std::endl << "nothing found" << std::endl << std::endl;
|
||||
}
|
||||
else {
|
||||
// Print result
|
||||
std::cout << line << std::endl << found.toLocal8Bit() << std::endl;
|
||||
somethingFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing is found
|
||||
if (!somethingFound)
|
||||
return U_ITEM_NOT_FOUND;
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
print_usage();
|
||||
return U_INVALID_PARAMETER;
|
||||
}
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
# Patch string format
|
||||
# FileGuid SectionType PatchType:FindPatternOrOffset:ReplacePattern
|
||||
# Please ensure that the latest symbol in patch string is space
|
||||
|
||||
# Possible section types:
|
||||
# PE32 image 10
|
||||
# Position-independent code 11
|
||||
# TE Image 12
|
||||
# DXE Dependency 13
|
||||
# Version information 14
|
||||
# User interface string 15
|
||||
# 16-bit code 16
|
||||
# Guided freeform 18
|
||||
# Raw data 19
|
||||
# PEI Dependency 1B
|
||||
# SMM Dependency 1C
|
||||
# Please do not try another section types, it can make the resulting image broken
|
||||
|
||||
# Possible patch types:
|
||||
# P - pattern-based, first parameter is a pattern to find, second - a pattern to replace
|
||||
# O - offset-based, first parameter is hexadecimal offset, second - a pattern to replace
|
||||
# Patterns can have . as "any possible value" symbol
|
||||
|
||||
#----------------------------------------------------------------------------------
|
||||
# OSX CPU Power Management patches
|
||||
# Remove lock from MSR 0xE2 register
|
||||
#----------------------------------------------------------------------------------
|
||||
|
||||
# PowerMgmtDxe | Haswell
|
||||
F7731B4C-58A2-4DF4-8980-5645D39ECE58 10 P:75080FBAE80F89442430:EB080FBAE80F89442430
|
||||
|
||||
# PowerMgmtDxe | Haswell-E
|
||||
F7731B4C-58A2-4DF4-8980-5645D39ECE58 10 P:0FBA6C24380F:0FBA7424380F
|
||||
|
||||
# PowerManagement | Sandy Bridge with ME 8.xx, Ivy Bridge
|
||||
8C783970-F02A-4A4D-AF09-8797A51EEC8D 10 P:75080FBAE80F89442430:EB080FBAE80F89442430
|
||||
# PowerManagement | New SB-E/IB-E
|
||||
8C783970-F02A-4A4D-AF09-8797A51EEC8D 10 P:0FBA6C24380F:0FBA7424380F
|
||||
|
||||
# CpuPei | Sandy Bridge with ME 7.xx, old SB-E/IB-E
|
||||
2BB5AFA9-FF33-417B-8497-CB773C2B93BF 10 P:800018EB050D0080:000018EB050D0000
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
/* uefipatch.cpp
|
||||
|
||||
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#include "uefipatch.h"
|
||||
|
||||
UEFIPatch::UEFIPatch(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
ffsEngine = new FfsEngine(this);
|
||||
model = ffsEngine->treeModel();
|
||||
}
|
||||
|
||||
UEFIPatch::~UEFIPatch()
|
||||
{
|
||||
delete ffsEngine;
|
||||
}
|
||||
|
||||
UINT8 UEFIPatch::patchFromFile(QString path)
|
||||
{
|
||||
QFileInfo patchInfo = QFileInfo("patches.txt");
|
||||
|
||||
if (!patchInfo.exists())
|
||||
return ERR_INVALID_FILE;
|
||||
|
||||
QFile file;
|
||||
file.setFileName("patches.txt");
|
||||
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||
return ERR_INVALID_FILE;
|
||||
|
||||
QFileInfo fileInfo = QFileInfo(path);
|
||||
|
||||
if (!fileInfo.exists())
|
||||
return ERR_FILE_OPEN;
|
||||
|
||||
QFile inputFile;
|
||||
inputFile.setFileName(path);
|
||||
|
||||
if (!inputFile.open(QFile::ReadOnly))
|
||||
return ERR_FILE_READ;
|
||||
|
||||
QByteArray buffer = inputFile.readAll();
|
||||
inputFile.close();
|
||||
|
||||
UINT8 result = ffsEngine->parseImageFile(buffer);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
UINT8 counter = 0;
|
||||
while (!file.atEnd()) {
|
||||
QByteArray line = file.readLine();
|
||||
// Use sharp sign as commentary
|
||||
if (line.count() == 0 || line[0] == '#')
|
||||
continue;
|
||||
|
||||
QList<QByteArray> list = line.split(' ');
|
||||
if (list.count() < 3)
|
||||
continue;
|
||||
|
||||
QUuid uuid = QUuid(list.at(0));
|
||||
QByteArray guid = QByteArray::fromRawData((const char*)&uuid.data1, sizeof(EFI_GUID));
|
||||
bool converted;
|
||||
UINT8 sectionType = (UINT8)list.at(1).toUShort(&converted, 16);
|
||||
if (!converted)
|
||||
return ERR_INVALID_PARAMETER;
|
||||
|
||||
QVector<PatchData> patches;
|
||||
|
||||
for (int i = 2; i < list.count(); i++) {
|
||||
QList<QByteArray> patchList = list.at(i).split(':');
|
||||
PatchData patch;
|
||||
patch.type = *(UINT8*)patchList.at(0).constData();
|
||||
if (patch.type == PATCH_TYPE_PATTERN) {
|
||||
patch.offset = 0xFFFFFFFF;
|
||||
patch.hexFindPattern = patchList.at(1);
|
||||
patch.hexReplacePattern = patchList.at(2);
|
||||
patches.append(patch);
|
||||
}
|
||||
else if (patch.type == PATCH_TYPE_OFFSET) {
|
||||
patch.offset = patchList.at(1).toUInt(NULL, 16);
|
||||
patch.hexReplacePattern = patchList.at(2);
|
||||
patches.append(patch);
|
||||
}
|
||||
else {
|
||||
// Ignore unknown patch type
|
||||
continue;
|
||||
}
|
||||
}
|
||||
result = patchFile(model->index(0, 0), guid, sectionType, patches);
|
||||
if (result && result != ERR_NOTHING_TO_PATCH)
|
||||
return result;
|
||||
counter++;
|
||||
}
|
||||
|
||||
QByteArray reconstructed;
|
||||
result = ffsEngine->reconstructImageFile(reconstructed);
|
||||
if (result)
|
||||
return result;
|
||||
if (reconstructed == buffer)
|
||||
return ERR_NOTHING_TO_PATCH;
|
||||
|
||||
QFile outputFile;
|
||||
outputFile.setFileName(path.append(".patched"));
|
||||
if (!outputFile.open(QFile::WriteOnly))
|
||||
return ERR_FILE_WRITE;
|
||||
|
||||
outputFile.resize(0);
|
||||
outputFile.write(reconstructed);
|
||||
outputFile.close();
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT8 UEFIPatch::patchFile(const QModelIndex & index, const QByteArray & fileGuid, const UINT8 sectionType, const QVector<PatchData> & patches)
|
||||
{
|
||||
|
||||
if (!model || !index.isValid())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
if (model->type(index) == Types::Section && model->subtype(index) == sectionType) {
|
||||
QModelIndex fileIndex = model->findParentOfType(index, Types::File);
|
||||
if (model->type(fileIndex) == Types::File &&
|
||||
model->header(fileIndex).left(sizeof(EFI_GUID)) == fileGuid)
|
||||
{
|
||||
return ffsEngine->patch(index, patches);
|
||||
}
|
||||
}
|
||||
|
||||
if (model->rowCount(index) > 0) {
|
||||
for (int i = 0; i < model->rowCount(index); i++) {
|
||||
UINT8 result = patchFile(index.child(i, 0), fileGuid, sectionType, patches);
|
||||
if (!result)
|
||||
break;
|
||||
else if (result != ERR_NOTHING_TO_PATCH)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_NOTHING_TO_PATCH;
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/* uefipatch.h
|
||||
|
||||
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __UEFIPATCH_H__
|
||||
#define __UEFIPATCH_H__
|
||||
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QFileInfo>
|
||||
#include <QUuid>
|
||||
|
||||
#include "../basetypes.h"
|
||||
#include "../ffs.h"
|
||||
#include "../ffsengine.h"
|
||||
|
||||
class UEFIPatch : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UEFIPatch(QObject *parent = 0);
|
||||
~UEFIPatch();
|
||||
|
||||
UINT8 patchFromFile(QString path);
|
||||
UINT8 patch(QString path, QString fileGuid, QString findPattern, QString replacePattern);
|
||||
|
||||
private:
|
||||
UINT8 patchFile(const QModelIndex & index, const QByteArray & fileGuid, const UINT8 sectionType, const QVector<PatchData> & patches);
|
||||
FfsEngine* ffsEngine;
|
||||
TreeModel* model;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,43 +0,0 @@
|
|||
QT += core
|
||||
QT -= gui
|
||||
|
||||
TARGET = UEFIPatch
|
||||
TEMPLATE = app
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
DEFINES += _CONSOLE
|
||||
|
||||
SOURCES += uefipatch_main.cpp \
|
||||
uefipatch.cpp \
|
||||
../types.cpp \
|
||||
../descriptor.cpp \
|
||||
../ffs.cpp \
|
||||
../ffsengine.cpp \
|
||||
../peimage.cpp \
|
||||
../treeitem.cpp \
|
||||
../treemodel.cpp \
|
||||
../LZMA/LzmaCompress.c \
|
||||
../LZMA/LzmaDecompress.c \
|
||||
../LZMA/SDK/C/LzFind.c \
|
||||
../LZMA/SDK/C/LzmaDec.c \
|
||||
../LZMA/SDK/C/LzmaEnc.c \
|
||||
../Tiano/EfiTianoDecompress.c \
|
||||
../Tiano/EfiTianoCompress.c \
|
||||
../Tiano/EfiTianoCompressLegacy.c
|
||||
|
||||
HEADERS += uefipatch.h \
|
||||
../basetypes.h \
|
||||
../descriptor.h \
|
||||
../gbe.h \
|
||||
../me.h \
|
||||
../ffs.h \
|
||||
../peimage.h \
|
||||
../types.h \
|
||||
../ffsengine.h \
|
||||
../treeitem.h \
|
||||
../treemodel.h \
|
||||
../LZMA/LzmaCompress.h \
|
||||
../LZMA/LzmaDecompress.h \
|
||||
../Tiano/EfiTianoDecompress.h \
|
||||
../Tiano/EfiTianoCompress.h
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/* uefipatch_main.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <iostream>
|
||||
#include "uefipatch.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
a.setOrganizationName("CodeRush");
|
||||
a.setOrganizationDomain("coderush.me");
|
||||
a.setApplicationName("UEFIPatch");
|
||||
|
||||
UEFIPatch w;
|
||||
UINT8 result = ERR_SUCCESS;
|
||||
UINT32 argumentsCount = a.arguments().length();
|
||||
|
||||
if (argumentsCount == 2) {
|
||||
result = w.patchFromFile(a.arguments().at(1));
|
||||
}
|
||||
else {
|
||||
std::cout << "UEFIPatch 0.3.9 - UEFI image file patching utility" << std::endl << std::endl <<
|
||||
"Usage: UEFIPatch image_file" << std::endl << std::endl <<
|
||||
"Patches will be read from patches.txt file\n";
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case ERR_SUCCESS:
|
||||
std::cout << "Image patched" << std::endl;
|
||||
break;
|
||||
case ERR_INVALID_PARAMETER:
|
||||
std::cout << "Function called with invalid parameter" << std::endl;
|
||||
break;
|
||||
case ERR_NOTHING_TO_PATCH:
|
||||
std::cout << "No patches can be applied to input file" << std::endl;
|
||||
break;
|
||||
case ERR_UNKNOWN_PATCH_TYPE:
|
||||
std::cout << "Unknown patch type" << std::endl;
|
||||
break;
|
||||
case ERR_PATCH_OFFSET_OUT_OF_BOUNDS:
|
||||
std::cout << "Patch offset out of bounds" << std::endl;
|
||||
break;
|
||||
case ERR_INVALID_SYMBOL:
|
||||
std::cout << "Pattern format mismatch" << std::endl;
|
||||
break;
|
||||
case ERR_INVALID_FILE:
|
||||
std::cout << "patches.txt file not found or can't be read" << std::endl;
|
||||
break;
|
||||
case ERR_FILE_OPEN:
|
||||
std::cout << "Input file not found" << std::endl;
|
||||
break;
|
||||
case ERR_FILE_READ:
|
||||
std::cout << "Input file can't be read" << std::endl;
|
||||
break;
|
||||
case ERR_FILE_WRITE:
|
||||
std::cout << "Output file can't be written" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cout << "Error " << result << std::endl;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
146
UEFITool/CMakeLists.txt
Normal file
|
@ -0,0 +1,146 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 3.22)
|
||||
|
||||
PROJECT(UEFITool LANGUAGES C CXX)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
SET(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
FIND_PACKAGE(Qt6 REQUIRED COMPONENTS Widgets)
|
||||
|
||||
SET(PROJECT_FORMS
|
||||
uefitool.ui
|
||||
searchdialog.ui
|
||||
hexviewdialog.ui
|
||||
gotobasedialog.ui
|
||||
gotoaddressdialog.ui
|
||||
)
|
||||
|
||||
SET(PROJECT_HEADERS
|
||||
uefitool.h
|
||||
hexspinbox.h
|
||||
searchdialog.h
|
||||
hexviewdialog.h
|
||||
gotobasedialog.h
|
||||
gotoaddressdialog.h
|
||||
)
|
||||
|
||||
SET(PROJECT_SOURCES
|
||||
icons/uefitool.icns
|
||||
uefitool.rc
|
||||
uefitool_main.cpp
|
||||
uefitool.cpp
|
||||
searchdialog.cpp
|
||||
hexviewdialog.cpp
|
||||
hexlineedit.cpp
|
||||
ffsfinder.cpp
|
||||
hexspinbox.cpp
|
||||
../common/fitparser.cpp
|
||||
../common/guiddatabase.cpp
|
||||
../common/nvram.cpp
|
||||
../common/nvramparser.cpp
|
||||
../common/meparser.cpp
|
||||
../common/ffsops.cpp
|
||||
../common/types.cpp
|
||||
../common/descriptor.cpp
|
||||
../common/ffs.cpp
|
||||
../common/peimage.cpp
|
||||
../common/utility.cpp
|
||||
../common/ffsbuilder.cpp
|
||||
../common/ffsparser.cpp
|
||||
../common/ffsreport.cpp
|
||||
../common/treeitem.cpp
|
||||
../common/treemodel.cpp
|
||||
../common/LZMA/LzmaCompress.c
|
||||
../common/LZMA/LzmaDecompress.c
|
||||
../common/LZMA/SDK/C/CpuArch.c
|
||||
../common/LZMA/SDK/C/Bra.c
|
||||
../common/LZMA/SDK/C/Bra86.c
|
||||
../common/LZMA/SDK/C/LzFind.c
|
||||
../common/LZMA/SDK/C/LzmaDec.c
|
||||
../common/LZMA/SDK/C/LzmaEnc.c
|
||||
../common/Tiano/EfiTianoDecompress.c
|
||||
../common/Tiano/EfiTianoCompress.c
|
||||
../common/Tiano/EfiTianoCompressLegacy.c
|
||||
../common/ustring.cpp
|
||||
../common/digest/sha1.c
|
||||
../common/digest/sha256.c
|
||||
../common/digest/sha512.c
|
||||
../common/digest/sm3.c
|
||||
../common/generated/ami_nvar.cpp
|
||||
../common/generated/apple_sysf.cpp
|
||||
../common/generated/dell_dvar.cpp
|
||||
../common/generated/edk2_vss.cpp
|
||||
../common/generated/edk2_vss2.cpp
|
||||
../common/generated/edk2_ftw.cpp
|
||||
../common/generated/insyde_fdc.cpp
|
||||
../common/generated/insyde_fdm.cpp
|
||||
../common/generated/ms_slic_marker.cpp
|
||||
../common/generated/ms_slic_pubkey.cpp
|
||||
../common/generated/phoenix_evsa.cpp
|
||||
../common/generated/phoenix_flm.cpp
|
||||
../common/generated/intel_acbp_v1.cpp
|
||||
../common/generated/intel_acbp_v2.cpp
|
||||
../common/generated/intel_keym_v1.cpp
|
||||
../common/generated/intel_keym_v2.cpp
|
||||
../common/generated/intel_acm.cpp
|
||||
../common/kaitai/kaitaistream.cpp
|
||||
../common/zlib/adler32.c
|
||||
../common/zlib/compress.c
|
||||
../common/zlib/crc32.c
|
||||
../common/zlib/deflate.c
|
||||
../common/zlib/gzclose.c
|
||||
../common/zlib/gzlib.c
|
||||
../common/zlib/gzread.c
|
||||
../common/zlib/gzwrite.c
|
||||
../common/zlib/inflate.c
|
||||
../common/zlib/infback.c
|
||||
../common/zlib/inftrees.c
|
||||
../common/zlib/inffast.c
|
||||
../common/zlib/trees.c
|
||||
../common/zlib/uncompr.c
|
||||
../common/zlib/zutil.c
|
||||
)
|
||||
|
||||
QT_ADD_RESOURCES(PROJECT_SOURCES
|
||||
uefitool.qrc
|
||||
)
|
||||
|
||||
ADD_DEFINITIONS(
|
||||
-DU_ENABLE_NVRAM_PARSING_SUPPORT
|
||||
-DU_ENABLE_ME_PARSING_SUPPORT
|
||||
-DU_ENABLE_FIT_PARSING_SUPPORT
|
||||
-DU_ENABLE_GUID_DATABASE_SUPPORT
|
||||
)
|
||||
|
||||
SET_SOURCE_FILES_PROPERTIES(icons/uefitool.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
|
||||
ADD_EXECUTABLE(UEFITool ${PROJECT_HEADERS} ${PROJECT_FORMS} ${PROJECT_SOURCES})
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(UEFITool PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
TARGET_LINK_LIBRARIES(UEFITool PRIVATE Qt6::Widgets)
|
||||
|
||||
ADD_SUBDIRECTORY(QHexView)
|
||||
TARGET_LINK_LIBRARIES(UEFITool PRIVATE QHexView)
|
||||
|
||||
SET_TARGET_PROPERTIES(UEFITool PROPERTIES
|
||||
WIN32_EXECUTABLE ON
|
||||
MACOSX_BUNDLE ON
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist"
|
||||
AUTOMOC ON
|
||||
AUTOUIC ON
|
||||
)
|
||||
|
||||
IF(UNIX AND (NOT APPLE) AND (NOT CYGWIN))
|
||||
SET_TARGET_PROPERTIES(UEFITool PROPERTIES OUTPUT_NAME uefitool)
|
||||
INSTALL(FILES icons/uefitool_16x16.png DESTINATION share/icons/hicolor/16x16/apps RENAME uefitool.png)
|
||||
INSTALL(FILES icons/uefitool_32x32.png DESTINATION share/icons/hicolor/32x32/apps RENAME uefitool.png)
|
||||
INSTALL(FILES icons/uefitool_64x64.png DESTINATION share/icons/hicolor/64x64/apps RENAME uefitool.png)
|
||||
INSTALL(FILES icons/uefitool_128x128.png DESTINATION share/icons/hicolor/128x128/apps RENAME uefitool.png)
|
||||
INSTALL(FILES icons/uefitool_256x256.png DESTINATION share/icons/hicolor/256x256/apps RENAME uefitool.png)
|
||||
INSTALL(FILES icons/uefitool_512x512.png DESTINATION share/icons/hicolor/512x512/apps RENAME uefitool.png)
|
||||
INSTALL(FILES uefitool.desktop DESTINATION share/applications)
|
||||
ENDIF()
|
||||
|
||||
INSTALL(TARGETS UEFITool BUNDLE DESTINATION "/Applications" )
|
33
UEFITool/Info.plist
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>*</string>
|
||||
</array>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>None</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>UEFITool</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>UEFITool NE</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>uefitool</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>me.coderush.UEFITool</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
91
UEFITool/QHexView/CMakeLists.txt
Normal file
|
@ -0,0 +1,91 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(QHexView)
|
||||
|
||||
option(QHEXVIEW_BUILD_EXAMPLE "Build Example Application" OFF)
|
||||
option(QHEXVIEW_USE_QT5 "Enable Qt5 build" OFF)
|
||||
option(QHEXVIEW_ENABLE_DIALOGS "BuiltIn dialogs" OFF)
|
||||
|
||||
if(QHEXVIEW_USE_QT5)
|
||||
find_package(Qt5 REQUIRED COMPONENTS Widgets)
|
||||
else()
|
||||
find_package(Qt6 COMPONENTS Widgets)
|
||||
|
||||
if(NOT Qt6_FOUND)
|
||||
find_package(Qt5 REQUIRED COMPONENTS Widgets)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC)
|
||||
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
CXX_STANDARD 11
|
||||
AUTOMOC ON
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
Qt::Widgets
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
"${PROJECT_SOURCE_DIR}/include"
|
||||
)
|
||||
|
||||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
include/QHexView/model/buffer/qdevicebuffer.h
|
||||
include/QHexView/model/buffer/qhexbuffer.h
|
||||
include/QHexView/model/buffer/qmappedfilebuffer.h
|
||||
include/QHexView/model/buffer/qmemorybuffer.h
|
||||
include/QHexView/model/buffer/qmemoryrefbuffer.h
|
||||
include/QHexView/model/commands/hexcommand.h
|
||||
include/QHexView/model/commands/insertcommand.h
|
||||
include/QHexView/model/commands/removecommand.h
|
||||
include/QHexView/model/commands/replacecommand.h
|
||||
include/QHexView/model/commands/replacecommand.h
|
||||
include/QHexView/model/qhexcursor.h
|
||||
include/QHexView/model/qhexdelegate.h
|
||||
include/QHexView/model/qhexdocument.h
|
||||
include/QHexView/model/qhexmetadata.h
|
||||
include/QHexView/model/qhexoptions.h
|
||||
include/QHexView/model/qhexutils.h
|
||||
include/QHexView/qhexview.h
|
||||
|
||||
PRIVATE
|
||||
src/model/commands/hexcommand.cpp
|
||||
src/model/commands/insertcommand.cpp
|
||||
src/model/commands/removecommand.cpp
|
||||
src/model/commands/replacecommand.cpp
|
||||
src/model/buffer/qdevicebuffer.cpp
|
||||
src/model/buffer/qhexbuffer.cpp
|
||||
src/model/buffer/qmemorybuffer.cpp
|
||||
src/model/buffer/qmemoryrefbuffer.cpp
|
||||
src/model/buffer/qmappedfilebuffer.cpp
|
||||
src/model/qhexdelegate.cpp
|
||||
src/model/qhexutils.cpp
|
||||
src/model/qhexcursor.cpp
|
||||
src/model/qhexmetadata.cpp
|
||||
src/model/qhexdocument.cpp
|
||||
src/qhexview.cpp
|
||||
)
|
||||
|
||||
if(QHEXVIEW_ENABLE_DIALOGS)
|
||||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
include/QHexView/dialogs/hexfinddialog.h
|
||||
src/dialogs/hexfinddialog.cpp
|
||||
)
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
QHEXVIEW_ENABLE_DIALOGS
|
||||
)
|
||||
endif()
|
||||
|
||||
if(QHEXVIEW_BUILD_EXAMPLE)
|
||||
add_subdirectory(example)
|
||||
endif()
|
20
UEFITool/QHexView/LICENSE
Normal file
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Dax89
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
56
UEFITool/QHexView/include/QHexView/dialogs/hexfinddialog.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QHexView/model/qhexutils.h>
|
||||
|
||||
class QRegularExpressionValidator;
|
||||
class QDoubleValidator;
|
||||
class QIntValidator;
|
||||
class QHexView;
|
||||
|
||||
class HexFindDialog: public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Type { Find, Replace };
|
||||
|
||||
public:
|
||||
explicit HexFindDialog(HexFindDialog::Type type = Type::Find,
|
||||
QHexView* parent = nullptr);
|
||||
QHexView* hexView() const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateFindOptions(int);
|
||||
void validateActions();
|
||||
void replace();
|
||||
void find();
|
||||
|
||||
private:
|
||||
bool prepareOptions(QString& q, QHexFindMode& mode, QHexFindDirection& fd);
|
||||
bool validateIntRange(uint v) const;
|
||||
void checkResult(const QString& q, qint64 offset, QHexFindDirection fd);
|
||||
void prepareTextMode(QLayout* l);
|
||||
void prepareHexMode(QLayout* l);
|
||||
void prepareIntMode(QLayout* l);
|
||||
void prepareFloatMode(QLayout* l);
|
||||
|
||||
private:
|
||||
QRegularExpressionValidator *m_hexvalidator, *m_hexpvalidator;
|
||||
QDoubleValidator* m_dblvalidator;
|
||||
QIntValidator* m_intvalidator;
|
||||
int m_oldidxbits{-1}, m_oldidxendian{-1};
|
||||
unsigned int m_findoptions{0};
|
||||
qint64 m_startoffset{-1};
|
||||
Type m_type;
|
||||
|
||||
private:
|
||||
static const QString BUTTONBOX;
|
||||
static const QString CBFINDMODE;
|
||||
static const QString LEFIND;
|
||||
static const QString LEREPLACE;
|
||||
static const QString HLAYOUT;
|
||||
static const QString GBOPTIONS;
|
||||
static const QString RBALL;
|
||||
static const QString RBFORWARD;
|
||||
static const QString RBBACKWARD;
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/buffer/qhexbuffer.h>
|
||||
|
||||
class QDeviceBuffer: public QHexBuffer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QDeviceBuffer(QObject* parent = nullptr);
|
||||
virtual ~QDeviceBuffer();
|
||||
uchar at(qint64 idx) override;
|
||||
qint64 length() const override;
|
||||
void insert(qint64 offset, const QByteArray& data) override;
|
||||
void replace(qint64 offset, const QByteArray& data) override;
|
||||
void remove(qint64 offset, int length) override;
|
||||
QByteArray read(qint64 offset, int length) override;
|
||||
bool read(QIODevice* device) override;
|
||||
void write(QIODevice* device) override;
|
||||
qint64 indexOf(const QByteArray& ba, qint64 from) override;
|
||||
qint64 lastIndexOf(const QByteArray& ba, qint64 from) override;
|
||||
|
||||
protected:
|
||||
QIODevice* m_device{nullptr};
|
||||
};
|
29
UEFITool/QHexView/include/QHexView/model/buffer/qhexbuffer.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <QIODevice>
|
||||
#include <QObject>
|
||||
|
||||
class QHexBuffer: public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QHexBuffer(QObject* parent = nullptr);
|
||||
bool isEmpty() const;
|
||||
|
||||
public:
|
||||
virtual uchar at(qint64 idx);
|
||||
virtual bool accept(qint64 idx) const;
|
||||
virtual void replace(qint64 offset, const QByteArray& data);
|
||||
virtual void read(char* data, int size);
|
||||
virtual void read(const QByteArray& ba);
|
||||
|
||||
public:
|
||||
virtual qint64 length() const = 0;
|
||||
virtual void insert(qint64 offset, const QByteArray& data) = 0;
|
||||
virtual void remove(qint64 offset, int length) = 0;
|
||||
virtual QByteArray read(qint64 offset, int length) = 0;
|
||||
virtual bool read(QIODevice* iodevice) = 0;
|
||||
virtual void write(QIODevice* iodevice) = 0;
|
||||
virtual qint64 indexOf(const QByteArray& ba, qint64 from) = 0;
|
||||
virtual qint64 lastIndexOf(const QByteArray& ba, qint64 from) = 0;
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/buffer/qdevicebuffer.h>
|
||||
|
||||
class QMappedFileBuffer: public QDeviceBuffer {
|
||||
public:
|
||||
explicit QMappedFileBuffer(QObject* parent = nullptr);
|
||||
virtual ~QMappedFileBuffer();
|
||||
|
||||
public:
|
||||
QByteArray read(qint64 offset, int length) override;
|
||||
bool read(QIODevice* iodevice) override;
|
||||
void write(QIODevice* iodevice) override;
|
||||
|
||||
private:
|
||||
void remap();
|
||||
|
||||
private:
|
||||
uchar* m_mappeddata{nullptr};
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/buffer/qhexbuffer.h>
|
||||
|
||||
class QMemoryBuffer: public QHexBuffer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QMemoryBuffer(QObject* parent = nullptr);
|
||||
uchar at(qint64 idx) override;
|
||||
qint64 length() const override;
|
||||
void insert(qint64 offset, const QByteArray& data) override;
|
||||
void remove(qint64 offset, int length) override;
|
||||
QByteArray read(qint64 offset, int length) override;
|
||||
bool read(QIODevice* device) override;
|
||||
void write(QIODevice* device) override;
|
||||
qint64 indexOf(const QByteArray& ba, qint64 from) override;
|
||||
qint64 lastIndexOf(const QByteArray& ba, qint64 from) override;
|
||||
|
||||
private:
|
||||
QByteArray m_buffer;
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/buffer/qdevicebuffer.h>
|
||||
|
||||
class QMemoryRefBuffer: public QDeviceBuffer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QMemoryRefBuffer(QObject* parent = nullptr);
|
||||
bool read(QIODevice* device) override;
|
||||
void write(QIODevice* device) override;
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/buffer/qhexbuffer.h>
|
||||
#include <QUndoCommand>
|
||||
|
||||
class QHexDocument;
|
||||
|
||||
class HexCommand: public QUndoCommand {
|
||||
public:
|
||||
HexCommand(QHexBuffer* buffer, QHexDocument* document,
|
||||
QUndoCommand* parent = nullptr);
|
||||
|
||||
protected:
|
||||
QHexDocument* m_hexdocument;
|
||||
QHexBuffer* m_buffer;
|
||||
qint64 m_offset;
|
||||
int m_length;
|
||||
QByteArray m_data;
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/commands/hexcommand.h>
|
||||
|
||||
class InsertCommand: public HexCommand {
|
||||
public:
|
||||
InsertCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset,
|
||||
const QByteArray& data, QUndoCommand* parent = nullptr);
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/commands/hexcommand.h>
|
||||
|
||||
class RemoveCommand: public HexCommand {
|
||||
public:
|
||||
RemoveCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset,
|
||||
int length, QUndoCommand* parent = nullptr);
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/commands/hexcommand.h>
|
||||
|
||||
class ReplaceCommand: public HexCommand {
|
||||
public:
|
||||
ReplaceCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset,
|
||||
const QByteArray& data, QUndoCommand* parent = nullptr);
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
private:
|
||||
QByteArray m_olddata;
|
||||
};
|
73
UEFITool/QHexView/include/QHexView/model/qhexcursor.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/qhexoptions.h>
|
||||
#include <QHexView/model/qhexutils.h>
|
||||
#include <QObject>
|
||||
|
||||
class QHexView;
|
||||
|
||||
class QHexCursor: public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Mode { Overwrite, Insert };
|
||||
|
||||
private:
|
||||
explicit QHexCursor(const QHexOptions* options, QHexView* parent = nullptr);
|
||||
|
||||
public:
|
||||
QHexView* hexView() const;
|
||||
Mode mode() const;
|
||||
qint64 line() const;
|
||||
qint64 column() const;
|
||||
qint64 offset() const;
|
||||
qint64 address() const;
|
||||
quint64 lineAddress() const;
|
||||
qint64 selectionStartOffset() const;
|
||||
qint64 selectionEndOffset() const;
|
||||
qint64 selectionLength() const;
|
||||
QHexPosition position() const;
|
||||
QHexPosition selectionStart() const;
|
||||
QHexPosition selectionEnd() const;
|
||||
QByteArray selectedBytes() const;
|
||||
bool hasSelection() const;
|
||||
bool isSelected(qint64 line, qint64 column) const;
|
||||
void setMode(Mode m);
|
||||
void move(qint64 offset);
|
||||
void move(qint64 line, qint64 column);
|
||||
void move(QHexPosition pos);
|
||||
void select(qint64 offset);
|
||||
void select(qint64 line, qint64 column);
|
||||
void select(QHexPosition pos);
|
||||
void selectSize(qint64 length);
|
||||
qint64 replace(const QVariant& oldvalue, const QVariant& newvalue,
|
||||
qint64 offset, QHexFindMode mode = QHexFindMode::Text,
|
||||
unsigned int options = QHexFindOptions::None,
|
||||
QHexFindDirection fd = QHexFindDirection::Forward) const;
|
||||
qint64 find(const QVariant& value, qint64 offset,
|
||||
QHexFindMode mode = QHexFindMode::Text,
|
||||
unsigned int options = QHexFindOptions::None,
|
||||
QHexFindDirection fd = QHexFindDirection::Forward) const;
|
||||
qint64 positionToOffset(QHexPosition pos) const;
|
||||
QHexPosition offsetToPosition(qint64 offset) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void cut(bool hex = false);
|
||||
void copy(bool hex = false) const;
|
||||
void paste(bool hex = false);
|
||||
void selectAll();
|
||||
void removeSelection();
|
||||
void clearSelection();
|
||||
void switchMode();
|
||||
|
||||
Q_SIGNALS:
|
||||
void positionChanged();
|
||||
void modeChanged();
|
||||
|
||||
private:
|
||||
const QHexOptions* m_options;
|
||||
Mode m_mode{Mode::Overwrite};
|
||||
QHexPosition m_position{}, m_selection{};
|
||||
|
||||
friend class QHexView;
|
||||
};
|
30
UEFITool/QHexView/include/QHexView/model/qhexdelegate.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/qhexutils.h>
|
||||
#include <QObject>
|
||||
#include <QTextCharFormat>
|
||||
|
||||
class QHexView;
|
||||
|
||||
class QHexDelegate: public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QHexDelegate(QObject* parent = nullptr);
|
||||
virtual ~QHexDelegate() = default;
|
||||
virtual QString addressHeader(const QHexView* hexview) const;
|
||||
virtual QString hexHeader(const QHexView* hexview) const;
|
||||
virtual QString asciiHeader(const QHexView* hexview) const;
|
||||
virtual void renderAddress(quint64 address, QTextCharFormat& cf,
|
||||
const QHexView* hexview) const;
|
||||
virtual void renderHeader(QTextBlockFormat& bf,
|
||||
const QHexView* hexview) const;
|
||||
virtual void renderHeaderPart(const QString& s, QHexArea area,
|
||||
QTextCharFormat& cf,
|
||||
const QHexView* hexview) const;
|
||||
virtual bool render(quint64 offset, quint8 b, QTextCharFormat& outcf,
|
||||
const QHexView* hexview) const;
|
||||
virtual bool paintSeparator(QPainter* painter, QLineF line,
|
||||
const QHexView* hexview) const;
|
||||
virtual void paint(QPainter* painter, const QHexView* hexview) const;
|
||||
};
|
102
UEFITool/QHexView/include/QHexView/model/qhexdocument.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHexView/model/buffer/qhexbuffer.h>
|
||||
#include <QHexView/model/qhexmetadata.h>
|
||||
#include <QUndoStack>
|
||||
|
||||
class QHexCursor;
|
||||
|
||||
class QHexDocument: public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class ChangeReason { Insert, Remove, Replace };
|
||||
enum class FindDirection { Forward, Backward };
|
||||
Q_ENUM(ChangeReason);
|
||||
Q_ENUM(FindDirection);
|
||||
|
||||
private:
|
||||
explicit QHexDocument(QHexBuffer* buffer, QObject* parent = nullptr);
|
||||
bool accept(qint64 idx) const;
|
||||
|
||||
public:
|
||||
bool isEmpty() const;
|
||||
bool isModified() const;
|
||||
bool canUndo() const;
|
||||
bool canRedo() const;
|
||||
void setData(const QByteArray& ba);
|
||||
void setData(QHexBuffer* buffer);
|
||||
qint64 length() const;
|
||||
qint64 indexOf(const QByteArray& ba, qint64 from = 0);
|
||||
qint64 lastIndexOf(const QByteArray& ba, qint64 from = 0);
|
||||
QByteArray read(qint64 offset, int len = 0) const;
|
||||
uchar at(int offset) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void clearModified();
|
||||
void undo();
|
||||
void redo();
|
||||
void insert(qint64 offset, uchar b);
|
||||
void replace(qint64 offset, uchar b);
|
||||
void insert(qint64 offset, const QByteArray& data);
|
||||
void replace(qint64 offset, const QByteArray& data);
|
||||
void remove(qint64 offset, int len);
|
||||
bool saveTo(QIODevice* device);
|
||||
|
||||
public:
|
||||
template<typename T, bool Owned = true>
|
||||
static QHexDocument* fromDevice(QIODevice* iodevice,
|
||||
QObject* parent = nullptr);
|
||||
template<typename T>
|
||||
static QHexDocument* fromMemory(char* data, int size,
|
||||
QObject* parent = nullptr);
|
||||
template<typename T>
|
||||
static QHexDocument* fromMemory(const QByteArray& ba,
|
||||
QObject* parent = nullptr);
|
||||
static QHexDocument* fromBuffer(QHexBuffer* buffer,
|
||||
QObject* parent = nullptr);
|
||||
static QHexDocument* fromLargeFile(QString filename,
|
||||
QObject* parent = nullptr);
|
||||
static QHexDocument* fromMappedFile(QString filename,
|
||||
QObject* parent = nullptr);
|
||||
static QHexDocument* fromFile(QString filename, QObject* parent = nullptr);
|
||||
static QHexDocument* create(QObject* parent = nullptr);
|
||||
|
||||
Q_SIGNALS:
|
||||
void modifiedChanged(bool modified);
|
||||
void canUndoChanged(bool canundo);
|
||||
void canRedoChanged(bool canredo);
|
||||
void dataChanged(const QByteArray& data, quint64 offset,
|
||||
QHexDocument::ChangeReason reason);
|
||||
void changed();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
QHexBuffer* m_buffer;
|
||||
QUndoStack m_undostack;
|
||||
|
||||
friend class QHexView;
|
||||
};
|
||||
|
||||
template<typename T, bool Owned>
|
||||
QHexDocument* QHexDocument::fromDevice(QIODevice* iodevice, QObject* parent) {
|
||||
QHexBuffer* hexbuffer = new T(parent);
|
||||
if(Owned)
|
||||
iodevice->setParent(hexbuffer);
|
||||
return hexbuffer->read(iodevice) ? new QHexDocument(hexbuffer, parent)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
QHexDocument* QHexDocument::fromMemory(char* data, int size, QObject* parent) {
|
||||
QHexBuffer* hexbuffer = new T();
|
||||
hexbuffer->read(data, size);
|
||||
return new QHexDocument(hexbuffer, parent);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
QHexDocument* QHexDocument::fromMemory(const QByteArray& ba, QObject* parent) {
|
||||
QHexBuffer* hexbuffer = new T();
|
||||
hexbuffer->read(ba);
|
||||
return new QHexDocument(hexbuffer, parent);
|
||||
}
|
92
UEFITool/QHexView/include/QHexView/model/qhexmetadata.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include <QColor>
|
||||
#include <QHash>
|
||||
#include <QHexView/model/qhexoptions.h>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <functional>
|
||||
|
||||
struct QHexMetadataItem {
|
||||
qint64 begin, end;
|
||||
QColor foreground, background;
|
||||
QString comment;
|
||||
};
|
||||
|
||||
using QHexMetadataLine = QList<QHexMetadataItem>;
|
||||
|
||||
class QHexMetadata: public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using ClearMetadataCallback = std::function<bool(QHexMetadataItem&)>;
|
||||
|
||||
private:
|
||||
explicit QHexMetadata(const QHexOptions* options,
|
||||
QObject* parent = nullptr);
|
||||
|
||||
public:
|
||||
const QHexMetadataLine* find(qint64 line) const;
|
||||
QString getComment(qint64 line, qint64 column) const;
|
||||
void removeMetadata(qint64 line);
|
||||
void removeBackground(qint64 line);
|
||||
void removeForeground(qint64 line);
|
||||
void removeComments(qint64 line);
|
||||
void unhighlight(qint64 line);
|
||||
void clear();
|
||||
|
||||
public:
|
||||
inline void setMetadata(qint64 begin, qint64 end, const QColor& fgcolor,
|
||||
const QColor& bgcolor, const QString& comment) {
|
||||
this->setMetadata({begin, end, fgcolor, bgcolor, comment});
|
||||
}
|
||||
|
||||
inline void setForeground(qint64 begin, qint64 end, const QColor& fgcolor) {
|
||||
this->setMetadata(begin, end, fgcolor, QColor(), QString());
|
||||
}
|
||||
|
||||
inline void setBackground(qint64 begin, qint64 end, const QColor& bgcolor) {
|
||||
this->setMetadata(begin, end, QColor(), bgcolor, QString());
|
||||
}
|
||||
|
||||
inline void setComment(qint64 begin, qint64 end, const QString& comment) {
|
||||
this->setMetadata(begin, end, QColor(), QColor(), comment);
|
||||
};
|
||||
|
||||
inline void setMetadataSize(qint64 begin, qint64 length,
|
||||
const QColor& fgcolor, const QColor& bgcolor,
|
||||
const QString& comment) {
|
||||
this->setMetadata({begin, begin + length, fgcolor, bgcolor, comment});
|
||||
}
|
||||
|
||||
inline void setForegroundSize(qint64 begin, qint64 length,
|
||||
const QColor& fgcolor) {
|
||||
this->setForeground(begin, begin + length, fgcolor);
|
||||
}
|
||||
|
||||
inline void setBackgroundSize(qint64 begin, qint64 length,
|
||||
const QColor& bgcolor) {
|
||||
this->setBackground(begin, begin + length, bgcolor);
|
||||
}
|
||||
|
||||
inline void setCommentSize(qint64 begin, qint64 length,
|
||||
const QString& comment) {
|
||||
this->setComment(begin, begin + length, comment);
|
||||
};
|
||||
|
||||
private:
|
||||
void copy(const QHexMetadata* metadata);
|
||||
void clearMetadata(qint64 line, ClearMetadataCallback&& cb);
|
||||
void setMetadata(const QHexMetadataItem& mi);
|
||||
void invalidate();
|
||||
|
||||
Q_SIGNALS:
|
||||
void changed();
|
||||
void cleared();
|
||||
|
||||
private:
|
||||
QHash<qint64, QHexMetadataLine> m_metadata;
|
||||
const QHexOptions* m_options;
|
||||
|
||||
friend class QHexView;
|
||||
};
|
56
UEFITool/QHexView/include/QHexView/model/qhexoptions.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
|
||||
#include <QChar>
|
||||
#include <QColor>
|
||||
#include <QHash>
|
||||
|
||||
namespace QHexFlags {
|
||||
|
||||
enum : unsigned int {
|
||||
None = (1 << 0),
|
||||
HSeparator = (1 << 1),
|
||||
VSeparator = (1 << 2),
|
||||
StyledHeader = (1 << 3),
|
||||
StyledAddress = (1 << 4),
|
||||
NoHeader = (1 << 5),
|
||||
HighlightAddress = (1 << 6),
|
||||
HighlightColumn = (1 << 7),
|
||||
|
||||
Separators = HSeparator | VSeparator,
|
||||
Styled = StyledHeader | StyledAddress,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
struct QHexColor {
|
||||
QColor foreground;
|
||||
QColor background;
|
||||
};
|
||||
|
||||
struct QHexOptions {
|
||||
// Appearance
|
||||
QChar unprintablechar{'.'};
|
||||
QChar invalidchar{'?'};
|
||||
QString addresslabel{""};
|
||||
QString hexlabel;
|
||||
QString asciilabel;
|
||||
quint64 baseaddress{0};
|
||||
unsigned int flags{QHexFlags::None};
|
||||
unsigned int linelength{0x10};
|
||||
unsigned int addresswidth{0};
|
||||
unsigned int grouplength{1};
|
||||
int scrollsteps{1};
|
||||
|
||||
// Colors & Styles
|
||||
QHash<quint8, QHexColor> bytecolors;
|
||||
QColor linealternatebackground;
|
||||
QColor linebackground;
|
||||
QColor headercolor;
|
||||
QColor commentcolor;
|
||||
QColor separatorcolor;
|
||||
|
||||
// Misc
|
||||
bool copybreak{true};
|
||||
|
||||
inline bool hasFlag(unsigned int flag) const { return flags & flag; }
|
||||
};
|
66
UEFITool/QHexView/include/QHexView/model/qhexutils.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
struct QHexOptions;
|
||||
class QHexView;
|
||||
|
||||
namespace QHexFindOptions {
|
||||
|
||||
enum : unsigned int {
|
||||
None = (1 << 0),
|
||||
CaseSensitive = (1 << 1),
|
||||
Int8 = (1 << 2),
|
||||
Int16 = (1 << 3),
|
||||
Int32 = (1 << 4),
|
||||
Int64 = (1 << 5),
|
||||
Float = (1 << 6),
|
||||
Double = (1 << 7),
|
||||
|
||||
BigEndian = (1 << 11),
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
enum class QHexFindMode { Text, Hex, Int, Float };
|
||||
enum class QHexFindDirection { All, Forward, Backward };
|
||||
enum class QHexArea { Header, Address, Hex, Ascii, Extra };
|
||||
|
||||
struct QHexPosition {
|
||||
qint64 line;
|
||||
qint64 column;
|
||||
static inline QHexPosition invalid() { return {-1, -1}; }
|
||||
inline bool isValid() const { return line >= 0 && column >= 0; }
|
||||
inline bool operator==(const QHexPosition& rhs) const {
|
||||
return (line == rhs.line) && (column == rhs.column);
|
||||
}
|
||||
inline bool operator!=(const QHexPosition& rhs) const {
|
||||
return (line != rhs.line) || (column != rhs.column);
|
||||
}
|
||||
};
|
||||
|
||||
namespace QHexUtils {
|
||||
|
||||
bool isHex(char ch);
|
||||
QByteArray toHex(const QByteArray& ba, char sep);
|
||||
QByteArray toHex(const QByteArray& ba);
|
||||
qint64 positionToOffset(const QHexOptions* options, QHexPosition pos);
|
||||
QHexPosition offsetToPosition(const QHexOptions* options, qint64 offset);
|
||||
bool checkPattern(QString pattern);
|
||||
|
||||
QPair<qint64, qint64> find(const QHexView* hexview, QVariant value,
|
||||
qint64 startoffset = 0,
|
||||
QHexFindMode mode = QHexFindMode::Text,
|
||||
unsigned int options = QHexFindOptions::None,
|
||||
QHexFindDirection fd = QHexFindDirection::Forward);
|
||||
|
||||
QPair<qint64, qint64>
|
||||
replace(const QHexView* hexview, QVariant oldvalue, QVariant newvalue,
|
||||
qint64 startoffset = 0, QHexFindMode mode = QHexFindMode::Text,
|
||||
unsigned int options = QHexFindOptions::None,
|
||||
QHexFindDirection fd = QHexFindDirection::Forward);
|
||||
|
||||
} // namespace QHexUtils
|
184
UEFITool/QHexView/include/QHexView/qhexview.h
Normal file
|
@ -0,0 +1,184 @@
|
|||
#pragma once
|
||||
|
||||
#define QHEXVIEW_VERSION 5.0
|
||||
|
||||
#include <QAbstractScrollArea>
|
||||
#include <QFontMetricsF>
|
||||
#include <QHexView/model/qhexcursor.h>
|
||||
#include <QHexView/model/qhexdelegate.h>
|
||||
#include <QHexView/model/qhexdocument.h>
|
||||
#include <QList>
|
||||
#include <QRectF>
|
||||
#include <QTextCharFormat>
|
||||
|
||||
#if defined(QHEXVIEW_ENABLE_DIALOGS)
|
||||
class HexFindDialog;
|
||||
#endif
|
||||
|
||||
class QHexView: public QAbstractScrollArea {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class CopyMode { Visual, HexArraySquare, HexArrayCurly, HexArrayChar };
|
||||
Q_ENUM(CopyMode);
|
||||
|
||||
public:
|
||||
explicit QHexView(QWidget* parent = nullptr);
|
||||
QRectF headerRect() const;
|
||||
QRectF addressRect() const;
|
||||
QRectF hexRect() const;
|
||||
QRectF asciiRect() const;
|
||||
QHexDocument* hexDocument() const;
|
||||
QHexCursor* hexCursor() const;
|
||||
const QHexMetadata* hexMetadata() const;
|
||||
QHexOptions options() const;
|
||||
QColor getReadableColor(QColor c) const;
|
||||
QByteArray selectedBytes() const;
|
||||
QByteArray getLine(qint64 line) const;
|
||||
unsigned int addressWidth() const;
|
||||
unsigned int lineLength() const;
|
||||
bool isModified() const;
|
||||
bool canUndo() const;
|
||||
bool canRedo() const;
|
||||
quint64 offset() const;
|
||||
quint64 address() const;
|
||||
QHexPosition positionFromOffset(quint64 offset) const;
|
||||
QHexPosition positionFromAddress(quint64 address) const;
|
||||
QHexPosition position() const;
|
||||
QHexPosition selectionStart() const;
|
||||
QHexPosition selectionEnd() const;
|
||||
quint64 selectionStartOffset() const;
|
||||
quint64 selectionEndOffset() const;
|
||||
quint64 baseAddress() const;
|
||||
quint64 lines() const;
|
||||
qint64 replace(const QVariant& oldvalue, const QVariant& newvalue,
|
||||
qint64 offset, QHexFindMode mode = QHexFindMode::Text,
|
||||
unsigned int options = QHexFindOptions::None,
|
||||
QHexFindDirection fd = QHexFindDirection::Forward) const;
|
||||
qint64 find(const QVariant& value, qint64 offset,
|
||||
QHexFindMode mode = QHexFindMode::Text,
|
||||
unsigned int options = QHexFindOptions::None,
|
||||
QHexFindDirection fd = QHexFindDirection::Forward) const;
|
||||
void setOptions(const QHexOptions& options);
|
||||
void setBaseAddress(quint64 baseaddress);
|
||||
void setDelegate(QHexDelegate* rd);
|
||||
void setDocument(QHexDocument* doc);
|
||||
void setData(const QByteArray& ba);
|
||||
void setData(QHexBuffer* buffer);
|
||||
void setCursorMode(QHexCursor::Mode mode);
|
||||
void setByteColor(quint8 b, QHexColor c);
|
||||
void setByteForeground(quint8 b, QColor c);
|
||||
void setByteBackground(quint8 b, QColor c);
|
||||
void setMetadata(qint64 begin, qint64 end, const QColor& fgcolor,
|
||||
const QColor& bgcolor, const QString& comment);
|
||||
void setForeground(qint64 begin, qint64 end, const QColor& fgcolor);
|
||||
void setBackground(qint64 begin, qint64 end, const QColor& bgcolor);
|
||||
void setComment(qint64 begin, qint64 end, const QString& comment);
|
||||
void setMetadataSize(qint64 begin, qint64 length, const QColor& fgcolor,
|
||||
const QColor& bgcolor, const QString& comment);
|
||||
void setForegroundSize(qint64 begin, qint64 length, const QColor& fgcolor);
|
||||
void setBackgroundSize(qint64 begin, qint64 length, const QColor& bgcolor);
|
||||
void setCommentSize(qint64 begin, qint64 length, const QString& comment);
|
||||
void removeMetadata(qint64 line);
|
||||
void removeBackground(qint64 line);
|
||||
void removeForeground(qint64 line);
|
||||
void removeComments(qint64 line);
|
||||
void unhighlight(qint64 line);
|
||||
void clearMetadata();
|
||||
|
||||
public Q_SLOTS:
|
||||
#if defined(QHEXVIEW_ENABLE_DIALOGS)
|
||||
void showFind();
|
||||
void showReplace();
|
||||
#endif
|
||||
void undo();
|
||||
void redo();
|
||||
void cut(bool hex = false);
|
||||
void copyAs(CopyMode mode = CopyMode::Visual) const;
|
||||
void copy(bool hex = false) const;
|
||||
void paste(bool hex = false);
|
||||
void clearModified();
|
||||
void selectAll();
|
||||
void removeSelection();
|
||||
void switchMode();
|
||||
void setAddressWidth(unsigned int w);
|
||||
void setLineLength(unsigned int l);
|
||||
void setGroupLength(unsigned int l);
|
||||
void setScrollSteps(int scrollsteps);
|
||||
void setReadOnly(bool r);
|
||||
void setAutoWidth(bool r);
|
||||
|
||||
private:
|
||||
void paint(QPainter* painter) const;
|
||||
void checkOptions();
|
||||
void checkState();
|
||||
void checkAndUpdate(bool calccolumns = false);
|
||||
void calcColumns();
|
||||
void ensureVisible();
|
||||
void drawSeparators(QPainter* p) const;
|
||||
void drawHeader(QTextCursor& c) const;
|
||||
void drawDocument(QTextCursor& c) const;
|
||||
QTextCharFormat drawFormat(QTextCursor& c, quint8 b, const QString& s,
|
||||
QHexArea area, qint64 line, qint64 column,
|
||||
bool applyformat) const;
|
||||
unsigned int calcAddressWidth() const;
|
||||
int visibleLines(bool absolute = false) const;
|
||||
qint64 getLastColumn(qint64 line) const;
|
||||
qint64 lastLine() const;
|
||||
qreal getNCellsWidth(int n) const;
|
||||
qreal hexColumnWidth() const;
|
||||
qreal hexColumnX() const;
|
||||
qreal asciiColumnX() const;
|
||||
qreal endColumnX() const;
|
||||
qreal cellWidth() const;
|
||||
qreal lineHeight() const;
|
||||
qint64 positionFromLineCol(qint64 line, qint64 col) const;
|
||||
QHexPosition positionFromPoint(QPoint pt) const;
|
||||
QPoint absolutePoint(QPoint pt) const;
|
||||
QHexArea areaFromPoint(QPoint pt) const;
|
||||
void moveNext(bool select = false);
|
||||
void movePrevious(bool select = false);
|
||||
bool keyPressMove(QKeyEvent* e);
|
||||
bool keyPressTextInput(QKeyEvent* e);
|
||||
bool keyPressAction(QKeyEvent* e);
|
||||
|
||||
protected:
|
||||
bool event(QEvent* e) override;
|
||||
void showEvent(QShowEvent* e) override;
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
void resizeEvent(QResizeEvent* e) override;
|
||||
void focusInEvent(QFocusEvent* e) override;
|
||||
void focusOutEvent(QFocusEvent* e) override;
|
||||
void mousePressEvent(QMouseEvent* e) override;
|
||||
void mouseMoveEvent(QMouseEvent* e) override;
|
||||
void wheelEvent(QWheelEvent* e) override;
|
||||
void keyPressEvent(QKeyEvent* e) override;
|
||||
|
||||
private:
|
||||
static QString reduced(const QString& s, int maxlen);
|
||||
static bool isColorLight(QColor c);
|
||||
|
||||
Q_SIGNALS:
|
||||
void dataChanged(const QByteArray& data, quint64 offset,
|
||||
QHexDocument::ChangeReason reason);
|
||||
void modifiedChanged(bool modified);
|
||||
void positionChanged();
|
||||
void modeChanged();
|
||||
|
||||
private:
|
||||
bool m_readonly{false}, m_writing{false}, m_autowidth{false};
|
||||
QHexArea m_currentarea{QHexArea::Ascii};
|
||||
QList<QRectF> m_hexcolumns;
|
||||
QFontMetricsF m_fontmetrics;
|
||||
QHexOptions m_options;
|
||||
QHexCursor* m_hexcursor{nullptr};
|
||||
QHexDocument* m_hexdocument{nullptr};
|
||||
QHexMetadata* m_hexmetadata{nullptr};
|
||||
QHexDelegate* m_hexdelegate{nullptr};
|
||||
#if defined(QHEXVIEW_ENABLE_DIALOGS)
|
||||
HexFindDialog *m_hexdlgfind{nullptr}, *m_hexdlgreplace{nullptr};
|
||||
#endif
|
||||
|
||||
friend class QHexDelegate;
|
||||
friend class QHexCursor;
|
||||
};
|
418
UEFITool/QHexView/src/dialogs/hexfinddialog.cpp
Normal file
|
@ -0,0 +1,418 @@
|
|||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHexView/dialogs/hexfinddialog.h>
|
||||
#include <QHexView/qhexview.h>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QList>
|
||||
#include <QMessageBox>
|
||||
#include <QPair>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionValidator>
|
||||
#include <QSpacerItem>
|
||||
#include <QStackedLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <limits>
|
||||
|
||||
const QString HexFindDialog::BUTTONBOX = "qhexview_buttonbox";
|
||||
const QString HexFindDialog::CBFINDMODE = "qhexview_cbfindmode";
|
||||
const QString HexFindDialog::LEFIND = "qhexview_lefind";
|
||||
const QString HexFindDialog::LEREPLACE = "qhexview_lereplace";
|
||||
const QString HexFindDialog::HLAYOUT = "qhexview_hlayout";
|
||||
const QString HexFindDialog::GBOPTIONS = "qhexview_gboptions";
|
||||
const QString HexFindDialog::RBALL = "qhexview_rball";
|
||||
const QString HexFindDialog::RBFORWARD = "qhexview_rbforward";
|
||||
const QString HexFindDialog::RBBACKWARD = "qhexview_rbbackward";
|
||||
|
||||
HexFindDialog::HexFindDialog(Type type, QHexView* parent)
|
||||
: QDialog{parent}, m_type{type} {
|
||||
m_hexvalidator = new QRegularExpressionValidator(
|
||||
QRegularExpression{"[0-9A-Fa-f ]+"}, this);
|
||||
m_hexpvalidator = new QRegularExpressionValidator(
|
||||
QRegularExpression{"[0-9A-Fa-f \\?]+"}, this);
|
||||
m_dblvalidator = new QDoubleValidator(this);
|
||||
m_intvalidator = new QIntValidator(this);
|
||||
|
||||
this->setWindowTitle(type == Type::Replace ? tr("Replace...")
|
||||
: tr("Find..."));
|
||||
|
||||
auto* vlayout = new QVBoxLayout(this);
|
||||
auto* gridlayout = new QGridLayout();
|
||||
|
||||
auto* cbfindmode = new QComboBox(this);
|
||||
cbfindmode->setObjectName(HexFindDialog::CBFINDMODE);
|
||||
cbfindmode->addItem("Text", static_cast<int>(QHexFindMode::Text));
|
||||
cbfindmode->addItem("Hex", static_cast<int>(QHexFindMode::Hex));
|
||||
cbfindmode->addItem("Int", static_cast<int>(QHexFindMode::Int));
|
||||
cbfindmode->addItem("Float", static_cast<int>(QHexFindMode::Float));
|
||||
|
||||
QLineEdit *lereplace = nullptr, *lefind = new QLineEdit(this);
|
||||
lefind->setObjectName(HexFindDialog::LEFIND);
|
||||
|
||||
gridlayout->addWidget(new QLabel(tr("Mode:"), this), 0, 0, Qt::AlignRight);
|
||||
gridlayout->addWidget(cbfindmode, 0, 1);
|
||||
gridlayout->addWidget(new QLabel(tr("Find:"), this), 1, 0, Qt::AlignRight);
|
||||
gridlayout->addWidget(lefind, 1, 1);
|
||||
|
||||
if(type == Type::Replace) {
|
||||
lereplace = new QLineEdit(this);
|
||||
lereplace->setObjectName(HexFindDialog::LEREPLACE);
|
||||
|
||||
gridlayout->addWidget(new QLabel(tr("Replace:"), this), 2, 0,
|
||||
Qt::AlignRight);
|
||||
gridlayout->addWidget(lereplace, 2, 1);
|
||||
}
|
||||
|
||||
vlayout->addLayout(gridlayout);
|
||||
|
||||
auto* gboptions = new QGroupBox(this);
|
||||
gboptions->setObjectName(HexFindDialog::GBOPTIONS);
|
||||
gboptions->setTitle(tr("Options"));
|
||||
gboptions->setLayout(new QStackedLayout());
|
||||
|
||||
QGroupBox* gbdirection = new QGroupBox(this);
|
||||
gbdirection->setTitle(tr("Find direction"));
|
||||
auto* gbvlayout = new QVBoxLayout(gbdirection);
|
||||
|
||||
auto* rball = new QRadioButton("All", gbdirection);
|
||||
rball->setObjectName(HexFindDialog::RBALL);
|
||||
auto* rbforward = new QRadioButton("Forward", gbdirection);
|
||||
rbforward->setObjectName(HexFindDialog::RBFORWARD);
|
||||
rbforward->setChecked(true);
|
||||
auto* rbbackward = new QRadioButton("Backward", gbdirection);
|
||||
rbbackward->setObjectName(HexFindDialog::RBBACKWARD);
|
||||
|
||||
gbvlayout->addWidget(rball);
|
||||
gbvlayout->addWidget(rbforward);
|
||||
gbvlayout->addWidget(rbbackward);
|
||||
gbvlayout->addSpacerItem(
|
||||
new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
|
||||
auto* hlayout = new QHBoxLayout();
|
||||
hlayout->setObjectName(HexFindDialog::HLAYOUT);
|
||||
hlayout->addWidget(gboptions, 1);
|
||||
hlayout->addWidget(gbdirection);
|
||||
vlayout->addLayout(hlayout, 1);
|
||||
|
||||
auto* buttonbox = new QDialogButtonBox(this);
|
||||
buttonbox->setOrientation(Qt::Horizontal);
|
||||
|
||||
if(type == Type::Replace)
|
||||
buttonbox->setStandardButtons(QDialogButtonBox::Ok |
|
||||
QDialogButtonBox::Apply |
|
||||
QDialogButtonBox::Cancel);
|
||||
else
|
||||
buttonbox->setStandardButtons(QDialogButtonBox::Ok |
|
||||
QDialogButtonBox::Cancel);
|
||||
|
||||
buttonbox->setObjectName(HexFindDialog::BUTTONBOX);
|
||||
buttonbox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
buttonbox->button(QDialogButtonBox::Ok)->setText(tr("Find"));
|
||||
|
||||
if(type == Type::Replace) {
|
||||
buttonbox->button(QDialogButtonBox::Apply)->setEnabled(false);
|
||||
buttonbox->button(QDialogButtonBox::Apply)->setText(tr("Replace"));
|
||||
}
|
||||
|
||||
vlayout->addWidget(buttonbox);
|
||||
|
||||
connect(lefind, &QLineEdit::textChanged, this,
|
||||
&HexFindDialog::validateActions);
|
||||
connect(cbfindmode, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &HexFindDialog::updateFindOptions);
|
||||
connect(buttonbox, &QDialogButtonBox::accepted, this, &HexFindDialog::find);
|
||||
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
connect(parent, &QHexView::positionChanged, this,
|
||||
[this]() { m_startoffset = -1; });
|
||||
|
||||
if(lereplace) {
|
||||
connect(buttonbox->button(QDialogButtonBox::Apply),
|
||||
&QPushButton::clicked, this, &HexFindDialog::replace);
|
||||
connect(lereplace, &QLineEdit::textChanged, this,
|
||||
&HexFindDialog::validateActions);
|
||||
}
|
||||
|
||||
this->prepareTextMode(gboptions->layout());
|
||||
this->prepareHexMode(gboptions->layout());
|
||||
this->prepareIntMode(gboptions->layout());
|
||||
this->prepareFloatMode(gboptions->layout());
|
||||
this->updateFindOptions(-1);
|
||||
}
|
||||
|
||||
QHexView* HexFindDialog::hexView() const {
|
||||
return qobject_cast<QHexView*>(this->parentWidget());
|
||||
}
|
||||
|
||||
void HexFindDialog::updateFindOptions(int) {
|
||||
QGroupBox* gboptions =
|
||||
this->findChild<QGroupBox*>(HexFindDialog::GBOPTIONS);
|
||||
|
||||
QLineEdit* lefind = this->findChild<QLineEdit*>(HexFindDialog::LEFIND);
|
||||
QLineEdit* lereplace =
|
||||
this->findChild<QLineEdit*>(HexFindDialog::LEREPLACE);
|
||||
lefind->clear();
|
||||
if(lereplace)
|
||||
lereplace->clear();
|
||||
|
||||
bool ok = false;
|
||||
QHexFindMode mode = static_cast<QHexFindMode>(
|
||||
this->findChild<QComboBox*>(HexFindDialog::CBFINDMODE)
|
||||
->currentData()
|
||||
.toInt(&ok));
|
||||
if(!ok)
|
||||
return;
|
||||
|
||||
m_findoptions = QHexFindOptions::None;
|
||||
m_oldidxbits = m_oldidxendian = -1;
|
||||
|
||||
auto* stack = qobject_cast<QStackedLayout*>(gboptions->layout());
|
||||
|
||||
switch(mode) {
|
||||
case QHexFindMode::Text: {
|
||||
lefind->setValidator(nullptr);
|
||||
if(lereplace)
|
||||
lereplace->setValidator(nullptr);
|
||||
|
||||
stack->setCurrentIndex(0);
|
||||
gboptions->setVisible(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case QHexFindMode::Hex: {
|
||||
lefind->setValidator(m_hexpvalidator);
|
||||
if(lereplace)
|
||||
lereplace->setValidator(m_hexvalidator);
|
||||
stack->setCurrentIndex(1);
|
||||
gboptions->setVisible(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case QHexFindMode::Int: {
|
||||
lefind->setValidator(m_intvalidator);
|
||||
if(lereplace)
|
||||
lereplace->setValidator(m_intvalidator);
|
||||
|
||||
stack->setCurrentIndex(2);
|
||||
gboptions->setVisible(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case QHexFindMode::Float: {
|
||||
lefind->setValidator(m_dblvalidator);
|
||||
if(lereplace)
|
||||
lereplace->setValidator(m_dblvalidator);
|
||||
|
||||
stack->setCurrentIndex(3);
|
||||
gboptions->setVisible(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HexFindDialog::validateIntRange(uint v) const {
|
||||
if(m_findoptions & QHexFindOptions::Int8)
|
||||
return !(v > std::numeric_limits<quint8>::max());
|
||||
if(m_findoptions & QHexFindOptions::Int16)
|
||||
return !(v > std::numeric_limits<quint16>::max());
|
||||
if(m_findoptions & QHexFindOptions::Int32)
|
||||
return !(v > std::numeric_limits<quint32>::max());
|
||||
return true;
|
||||
}
|
||||
|
||||
void HexFindDialog::checkResult(const QString& q, qint64 offset,
|
||||
QHexFindDirection fd) {
|
||||
if(offset == -1) {
|
||||
QMessageBox::information(this, tr("Not found"),
|
||||
tr("Cannot find '%1'").arg(q));
|
||||
return;
|
||||
}
|
||||
|
||||
if(fd == QHexFindDirection::Backward)
|
||||
m_startoffset = this->hexView()->selectionStartOffset() - 1;
|
||||
else
|
||||
m_startoffset = this->hexView()->selectionEndOffset() + 1;
|
||||
}
|
||||
|
||||
void HexFindDialog::validateActions() {
|
||||
auto mode = static_cast<QHexFindMode>(
|
||||
this->findChild<QComboBox*>(HexFindDialog::CBFINDMODE)
|
||||
->currentData()
|
||||
.toUInt());
|
||||
auto* lefind = this->findChild<QLineEdit*>(HexFindDialog::LEFIND);
|
||||
auto* lereplace = this->findChild<QLineEdit*>(HexFindDialog::LEREPLACE);
|
||||
auto* buttonbox =
|
||||
this->findChild<QDialogButtonBox*>(HexFindDialog::BUTTONBOX);
|
||||
|
||||
bool findenable = false, replaceenable = false;
|
||||
|
||||
switch(mode) {
|
||||
case QHexFindMode::Hex:
|
||||
findenable = QHexUtils::checkPattern(lefind->text());
|
||||
replaceenable = findenable;
|
||||
break;
|
||||
|
||||
case QHexFindMode::Float: {
|
||||
lefind->text().toFloat(&findenable);
|
||||
if(lereplace && findenable)
|
||||
lereplace->text().toFloat(&replaceenable);
|
||||
break;
|
||||
}
|
||||
|
||||
case QHexFindMode::Int: {
|
||||
auto v = lefind->text().toUInt(&findenable);
|
||||
if(findenable && !this->validateIntRange(v))
|
||||
findenable = false;
|
||||
if(lereplace && findenable)
|
||||
lereplace->text().toUInt(&replaceenable);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
findenable = !lefind->text().isEmpty();
|
||||
replaceenable = findenable;
|
||||
break;
|
||||
}
|
||||
|
||||
if(lereplace)
|
||||
buttonbox->button(QDialogButtonBox::Apply)->setEnabled(replaceenable);
|
||||
buttonbox->button(QDialogButtonBox::Ok)->setEnabled(findenable);
|
||||
}
|
||||
|
||||
void HexFindDialog::replace() {
|
||||
QString q1;
|
||||
QHexFindMode mode;
|
||||
QHexFindDirection fd;
|
||||
|
||||
if(!this->prepareOptions(q1, mode, fd))
|
||||
return;
|
||||
|
||||
QString q2 = this->findChild<QLineEdit*>(HexFindDialog::LEREPLACE)->text();
|
||||
auto offset = this->hexView()->hexCursor()->replace(
|
||||
q1, q2, m_startoffset > -1 ? m_startoffset : this->hexView()->offset(),
|
||||
mode, m_findoptions, fd);
|
||||
this->checkResult(q1, offset, fd);
|
||||
}
|
||||
|
||||
void HexFindDialog::find() {
|
||||
QString q;
|
||||
QHexFindMode mode;
|
||||
QHexFindDirection fd;
|
||||
|
||||
if(!this->prepareOptions(q, mode, fd))
|
||||
return;
|
||||
|
||||
auto offset = this->hexView()->hexCursor()->find(
|
||||
q, m_startoffset > -1 ? m_startoffset : this->hexView()->offset(), mode,
|
||||
m_findoptions, fd);
|
||||
this->checkResult(q, offset, fd);
|
||||
}
|
||||
|
||||
bool HexFindDialog::prepareOptions(QString& q, QHexFindMode& mode,
|
||||
QHexFindDirection& fd) {
|
||||
q = this->findChild<QLineEdit*>(HexFindDialog::LEFIND)->text();
|
||||
mode = static_cast<QHexFindMode>(
|
||||
this->findChild<QComboBox*>(HexFindDialog::CBFINDMODE)
|
||||
->currentData()
|
||||
.toUInt());
|
||||
|
||||
if(mode == QHexFindMode::Hex && !QHexUtils::checkPattern(q)) {
|
||||
QMessageBox::warning(this, tr("Pattern Error"),
|
||||
tr("Hex pattern '%1' is not valid").arg(q));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(this->findChild<QRadioButton*>(HexFindDialog::RBBACKWARD)->isChecked())
|
||||
fd = QHexFindDirection::Backward;
|
||||
else if(this->findChild<QRadioButton*>(HexFindDialog::RBFORWARD)
|
||||
->isChecked())
|
||||
fd = QHexFindDirection::Forward;
|
||||
else
|
||||
fd = QHexFindDirection::All;
|
||||
return true;
|
||||
}
|
||||
|
||||
void HexFindDialog::prepareTextMode(QLayout* l) {
|
||||
auto* cbcasesensitive = new QCheckBox("Case sensitive");
|
||||
|
||||
connect(cbcasesensitive, &QCheckBox::stateChanged, this, [this](int state) {
|
||||
if(state == Qt::Checked)
|
||||
m_findoptions |= QHexFindOptions::CaseSensitive;
|
||||
else
|
||||
m_findoptions &= ~QHexFindOptions::CaseSensitive;
|
||||
});
|
||||
|
||||
auto* vlayout = new QVBoxLayout(new QWidget());
|
||||
vlayout->addWidget(cbcasesensitive);
|
||||
l->addWidget(vlayout->parentWidget());
|
||||
}
|
||||
|
||||
void HexFindDialog::prepareHexMode(QLayout* l) { l->addWidget(new QWidget()); }
|
||||
|
||||
void HexFindDialog::prepareIntMode(QLayout* l) {
|
||||
static const QList<QPair<QString, unsigned int>> INT_TYPES = {
|
||||
qMakePair<QString, unsigned int>("(any)", 0),
|
||||
qMakePair<QString, unsigned int>("8", QHexFindOptions::Int8),
|
||||
qMakePair<QString, unsigned int>("16", QHexFindOptions::Int16),
|
||||
qMakePair<QString, unsigned int>("32", QHexFindOptions::Int32),
|
||||
qMakePair<QString, unsigned int>("64", QHexFindOptions::Int64)};
|
||||
|
||||
auto* cbbits = new QComboBox();
|
||||
for(const auto& it : INT_TYPES)
|
||||
cbbits->addItem(it.first, it.second);
|
||||
|
||||
connect(cbbits, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
[this, cbbits](int index) {
|
||||
if(m_oldidxbits > -1)
|
||||
m_findoptions &= ~cbbits->itemData(m_oldidxbits).toUInt();
|
||||
m_findoptions |= cbbits->itemData(index).toUInt();
|
||||
m_oldidxbits = index;
|
||||
});
|
||||
|
||||
auto* cbendian = new QComboBox();
|
||||
cbendian->addItem("Little Endian", 0);
|
||||
cbendian->addItem("Big Endian", QHexFindOptions::BigEndian);
|
||||
|
||||
connect(cbendian, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
[this, cbendian](int index) {
|
||||
if(m_oldidxendian > -1)
|
||||
m_findoptions &=
|
||||
~cbendian->itemData(m_oldidxendian).toUInt();
|
||||
m_findoptions |= cbendian->itemData(index).toUInt();
|
||||
m_oldidxendian = index;
|
||||
});
|
||||
|
||||
auto* vlayout = new QVBoxLayout(new QWidget());
|
||||
|
||||
QGridLayout* gl = new QGridLayout();
|
||||
gl->addWidget(new QLabel("Type:"), 0, 0, Qt::AlignRight);
|
||||
gl->addWidget(cbbits, 0, 1);
|
||||
gl->addWidget(new QLabel("Endian:"), 1, 0, Qt::AlignRight);
|
||||
gl->addWidget(cbendian, 1, 1);
|
||||
vlayout->addLayout(gl);
|
||||
|
||||
l->addWidget(vlayout->parentWidget());
|
||||
}
|
||||
|
||||
void HexFindDialog::prepareFloatMode(QLayout* l) {
|
||||
static const QList<QPair<QString, unsigned int>> FLOAT_TYPES = {
|
||||
qMakePair<QString, unsigned int>("float", QHexFindOptions::Float),
|
||||
qMakePair<QString, unsigned int>("double", QHexFindOptions::Double)};
|
||||
|
||||
bool first = true;
|
||||
auto* vlayout = new QVBoxLayout(new QWidget());
|
||||
|
||||
for(const auto& ft : FLOAT_TYPES) {
|
||||
auto* rb = new QRadioButton(ft.first);
|
||||
rb->setChecked(first);
|
||||
vlayout->addWidget(rb);
|
||||
first = false;
|
||||
}
|
||||
|
||||
l->addWidget(vlayout->parentWidget());
|
||||
}
|
118
UEFITool/QHexView/src/model/buffer/qdevicebuffer.cpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
#include <QHexView/model/buffer/qdevicebuffer.h>
|
||||
#include <QIODevice>
|
||||
#include <limits>
|
||||
|
||||
QDeviceBuffer::QDeviceBuffer(QObject* parent): QHexBuffer{parent} {}
|
||||
|
||||
QDeviceBuffer::~QDeviceBuffer() {
|
||||
if(!m_device)
|
||||
return;
|
||||
|
||||
if(m_device->parent() == this) {
|
||||
if(m_device->isOpen())
|
||||
m_device->close();
|
||||
m_device->deleteLater();
|
||||
}
|
||||
|
||||
m_device = nullptr;
|
||||
}
|
||||
|
||||
uchar QDeviceBuffer::at(qint64 idx) {
|
||||
m_device->seek(idx);
|
||||
|
||||
char c = '\0';
|
||||
m_device->getChar(&c);
|
||||
return static_cast<uchar>(c);
|
||||
}
|
||||
|
||||
qint64 QDeviceBuffer::length() const { return m_device->size(); }
|
||||
|
||||
void QDeviceBuffer::insert(qint64 offset, const QByteArray& data) {
|
||||
Q_UNUSED(offset)
|
||||
Q_UNUSED(data)
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
void QDeviceBuffer::replace(qint64 offset, const QByteArray& data) {
|
||||
m_device->seek(offset);
|
||||
m_device->write(data);
|
||||
}
|
||||
|
||||
void QDeviceBuffer::remove(qint64 offset, int length) {
|
||||
Q_UNUSED(offset)
|
||||
Q_UNUSED(length)
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
QByteArray QDeviceBuffer::read(qint64 offset, int length) {
|
||||
m_device->seek(offset);
|
||||
return m_device->read(length);
|
||||
}
|
||||
|
||||
bool QDeviceBuffer::read(QIODevice* device) {
|
||||
m_device = device;
|
||||
if(!m_device)
|
||||
return false;
|
||||
if(!m_device->isOpen())
|
||||
m_device->open(QIODevice::ReadWrite);
|
||||
return m_device->isOpen();
|
||||
}
|
||||
|
||||
void QDeviceBuffer::write(QIODevice* device) {
|
||||
Q_UNUSED(device)
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
qint64 QDeviceBuffer::indexOf(const QByteArray& ba, qint64 from) {
|
||||
const auto MAX = std::numeric_limits<int>::max();
|
||||
qint64 idx = -1;
|
||||
|
||||
if(from < m_device->size()) {
|
||||
idx = from;
|
||||
m_device->seek(from);
|
||||
|
||||
while(idx < m_device->size()) {
|
||||
QByteArray data = m_device->read(MAX);
|
||||
int sidx = data.indexOf(ba);
|
||||
|
||||
if(sidx >= 0) {
|
||||
idx += sidx;
|
||||
break;
|
||||
}
|
||||
|
||||
if(idx + data.size() >= m_device->size())
|
||||
return -1;
|
||||
m_device->seek(m_device->pos() + data.size() - ba.size());
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
qint64 QDeviceBuffer::lastIndexOf(const QByteArray& ba, qint64 from) {
|
||||
const auto MAX = std::numeric_limits<int>::max();
|
||||
qint64 idx = -1;
|
||||
|
||||
if(from >= 0 && ba.size() < MAX) {
|
||||
qint64 currpos = from;
|
||||
|
||||
while(currpos >= 0) {
|
||||
qint64 readpos = (currpos < MAX) ? 0 : currpos - MAX;
|
||||
m_device->seek(readpos);
|
||||
|
||||
QByteArray data = m_device->read(currpos - readpos);
|
||||
int lidx = data.lastIndexOf(ba, from);
|
||||
|
||||
if(lidx >= 0) {
|
||||
idx = readpos + lidx;
|
||||
break;
|
||||
}
|
||||
|
||||
if(readpos <= 0)
|
||||
break;
|
||||
currpos = readpos + ba.size();
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
36
UEFITool/QHexView/src/model/buffer/qhexbuffer.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include <QBuffer>
|
||||
#include <QHexView/model/buffer/qhexbuffer.h>
|
||||
|
||||
QHexBuffer::QHexBuffer(QObject* parent): QObject{parent} {}
|
||||
uchar QHexBuffer::at(qint64 idx) { return this->read(idx, 1).at(0); }
|
||||
bool QHexBuffer::isEmpty() const { return this->length() <= 0; }
|
||||
|
||||
void QHexBuffer::replace(qint64 offset, const QByteArray& data) {
|
||||
this->remove(offset, data.length());
|
||||
this->insert(offset, data);
|
||||
}
|
||||
|
||||
bool QHexBuffer::accept(qint64 idx) const {
|
||||
Q_UNUSED(idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
void QHexBuffer::read(char* data, int size) {
|
||||
QBuffer* buffer = new QBuffer(this);
|
||||
buffer->setData(data, size);
|
||||
|
||||
if(!buffer->isOpen())
|
||||
buffer->open(QBuffer::ReadWrite);
|
||||
|
||||
this->read(buffer);
|
||||
}
|
||||
|
||||
void QHexBuffer::read(const QByteArray& ba) {
|
||||
QBuffer* buffer = new QBuffer(this);
|
||||
|
||||
buffer->setData(ba);
|
||||
if(!buffer->isOpen())
|
||||
buffer->open(QBuffer::ReadWrite);
|
||||
|
||||
this->read(buffer);
|
||||
}
|
51
UEFITool/QHexView/src/model/buffer/qmappedfilebuffer.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include <QFile>
|
||||
#include <QHexView/model/buffer/qmappedfilebuffer.h>
|
||||
|
||||
QMappedFileBuffer::QMappedFileBuffer(QObject* parent): QDeviceBuffer{parent} {}
|
||||
|
||||
QMappedFileBuffer::~QMappedFileBuffer() {
|
||||
if((m_device && (m_device->parent() == this)) && m_mappeddata) {
|
||||
QFile* f = qobject_cast<QFile*>(m_device);
|
||||
f->unmap(m_mappeddata);
|
||||
}
|
||||
|
||||
m_mappeddata = nullptr;
|
||||
}
|
||||
|
||||
QByteArray QMappedFileBuffer::read(qint64 offset, int length) {
|
||||
if(offset >= this->length())
|
||||
return {};
|
||||
|
||||
if(offset + length >= this->length())
|
||||
length = this->length() - offset;
|
||||
|
||||
return QByteArray::fromRawData(
|
||||
reinterpret_cast<const char*>(m_mappeddata + offset), length);
|
||||
}
|
||||
|
||||
bool QMappedFileBuffer::read(QIODevice* iodevice) {
|
||||
m_device = qobject_cast<QFile*>(iodevice);
|
||||
if(!m_device || !QDeviceBuffer::read(iodevice))
|
||||
return false;
|
||||
|
||||
this->remap();
|
||||
return m_mappeddata;
|
||||
}
|
||||
|
||||
void QMappedFileBuffer::write(QIODevice* iodevice) {
|
||||
if(iodevice == m_device)
|
||||
this->remap();
|
||||
else
|
||||
iodevice->write(reinterpret_cast<const char*>(m_mappeddata),
|
||||
m_device->size());
|
||||
}
|
||||
|
||||
void QMappedFileBuffer::remap() {
|
||||
QFile* f = qobject_cast<QFile*>(m_device);
|
||||
if(!f)
|
||||
return;
|
||||
|
||||
if(m_mappeddata)
|
||||
f->unmap(m_mappeddata);
|
||||
m_mappeddata = f->map(0, f->size());
|
||||
}
|
39
UEFITool/QHexView/src/model/buffer/qmemorybuffer.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include <QHexView/model/buffer/qmemorybuffer.h>
|
||||
#include <QIODevice>
|
||||
|
||||
QMemoryBuffer::QMemoryBuffer(QObject* parent): QHexBuffer{parent} {}
|
||||
|
||||
uchar QMemoryBuffer::at(qint64 idx) {
|
||||
return static_cast<uchar>(m_buffer.at(idx));
|
||||
}
|
||||
|
||||
qint64 QMemoryBuffer::length() const {
|
||||
return static_cast<qint64>(m_buffer.length());
|
||||
}
|
||||
|
||||
void QMemoryBuffer::insert(qint64 offset, const QByteArray& data) {
|
||||
m_buffer.insert(static_cast<int>(offset), data);
|
||||
}
|
||||
|
||||
void QMemoryBuffer::remove(qint64 offset, int length) {
|
||||
m_buffer.remove(static_cast<int>(offset), length);
|
||||
}
|
||||
|
||||
QByteArray QMemoryBuffer::read(qint64 offset, int length) {
|
||||
return m_buffer.mid(static_cast<int>(offset), length);
|
||||
}
|
||||
|
||||
bool QMemoryBuffer::read(QIODevice* device) {
|
||||
m_buffer = device->readAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
void QMemoryBuffer::write(QIODevice* device) { device->write(m_buffer); }
|
||||
|
||||
qint64 QMemoryBuffer::indexOf(const QByteArray& ba, qint64 from) {
|
||||
return m_buffer.indexOf(ba, static_cast<int>(from));
|
||||
}
|
||||
|
||||
qint64 QMemoryBuffer::lastIndexOf(const QByteArray& ba, qint64 from) {
|
||||
return m_buffer.lastIndexOf(ba, static_cast<int>(from));
|
||||
}
|
26
UEFITool/QHexView/src/model/buffer/qmemoryrefbuffer.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <QBuffer>
|
||||
#include <QHexView/model/buffer/qmemoryrefbuffer.h>
|
||||
|
||||
QMemoryRefBuffer::QMemoryRefBuffer(QObject* parent): QDeviceBuffer{parent} {}
|
||||
|
||||
bool QMemoryRefBuffer::read(QIODevice* device) {
|
||||
m_device = qobject_cast<QBuffer*>(device);
|
||||
|
||||
if(m_device) {
|
||||
m_device->setParent(this);
|
||||
return QDeviceBuffer::read(device);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QMemoryRefBuffer::write(QIODevice* device) {
|
||||
if(!m_device || m_device == device)
|
||||
return;
|
||||
|
||||
static const int CHUNK_SIZE = 4096;
|
||||
m_device->seek(0);
|
||||
|
||||
while(!m_device->atEnd())
|
||||
device->write(m_device->read(CHUNK_SIZE));
|
||||
}
|
6
UEFITool/QHexView/src/model/commands/hexcommand.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include <QHexView/model/commands/hexcommand.h>
|
||||
|
||||
HexCommand::HexCommand(QHexBuffer* buffer, QHexDocument* document,
|
||||
QUndoCommand* parent)
|
||||
: QUndoCommand(parent), m_hexdocument(document), m_buffer(buffer),
|
||||
m_offset(0), m_length(0) {}
|
18
UEFITool/QHexView/src/model/commands/insertcommand.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <QHexView/model/commands/insertcommand.h>
|
||||
#include <QHexView/model/qhexdocument.h>
|
||||
|
||||
InsertCommand::InsertCommand(QHexBuffer* buffer, QHexDocument* document,
|
||||
qint64 offset, const QByteArray& data,
|
||||
QUndoCommand* parent)
|
||||
: HexCommand(buffer, document, parent) {
|
||||
m_offset = offset;
|
||||
m_data = data;
|
||||
}
|
||||
|
||||
void InsertCommand::undo() {
|
||||
m_buffer->remove(m_offset, m_data.length());
|
||||
Q_EMIT m_hexdocument->dataChanged(m_data, m_offset,
|
||||
QHexDocument::ChangeReason::Remove);
|
||||
}
|
||||
|
||||
void InsertCommand::redo() { m_buffer->insert(m_offset, m_data); }
|
20
UEFITool/QHexView/src/model/commands/removecommand.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <QHexView/model/commands/removecommand.h>
|
||||
#include <QHexView/model/qhexdocument.h>
|
||||
|
||||
RemoveCommand::RemoveCommand(QHexBuffer* buffer, QHexDocument* document,
|
||||
qint64 offset, int length, QUndoCommand* parent)
|
||||
: HexCommand(buffer, document, parent) {
|
||||
m_offset = offset;
|
||||
m_length = length;
|
||||
}
|
||||
|
||||
void RemoveCommand::undo() {
|
||||
m_buffer->insert(m_offset, m_data);
|
||||
Q_EMIT m_hexdocument->dataChanged(m_data, m_offset,
|
||||
QHexDocument::ChangeReason::Insert);
|
||||
}
|
||||
|
||||
void RemoveCommand::redo() {
|
||||
m_data = m_buffer->read(m_offset, m_length); // Backup data
|
||||
m_buffer->remove(m_offset, m_length);
|
||||
}
|
21
UEFITool/QHexView/src/model/commands/replacecommand.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include <QHexView/model/commands/replacecommand.h>
|
||||
#include <QHexView/model/qhexdocument.h>
|
||||
|
||||
ReplaceCommand::ReplaceCommand(QHexBuffer* buffer, QHexDocument* document,
|
||||
qint64 offset, const QByteArray& data,
|
||||
QUndoCommand* parent)
|
||||
: HexCommand(buffer, document, parent) {
|
||||
m_offset = offset;
|
||||
m_data = data;
|
||||
}
|
||||
|
||||
void ReplaceCommand::undo() {
|
||||
m_buffer->replace(m_offset, m_olddata);
|
||||
Q_EMIT m_hexdocument->dataChanged(m_olddata, m_offset,
|
||||
QHexDocument::ChangeReason::Replace);
|
||||
}
|
||||
|
||||
void ReplaceCommand::redo() {
|
||||
m_olddata = m_buffer->read(m_offset, m_data.length());
|
||||
m_buffer->replace(m_offset, m_data);
|
||||
}
|
182
UEFITool/QHexView/src/model/qhexcursor.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
#include <QHexView/model/qhexcursor.h>
|
||||
#include <QHexView/model/qhexdocument.h>
|
||||
#include <QHexView/qhexview.h>
|
||||
|
||||
/*
|
||||
* https://stackoverflow.com/questions/10803043/inverse-column-row-major-order-transformation
|
||||
*
|
||||
* If the index is calculated as:
|
||||
* offset = row + column*NUMROWS
|
||||
* then the inverse would be:
|
||||
* row = offset % NUMROWS
|
||||
* column = offset / NUMROWS
|
||||
* where % is modulus, and / is integer division.
|
||||
*/
|
||||
|
||||
QHexCursor::QHexCursor(const QHexOptions* options, QHexView* parent)
|
||||
: QObject(parent), m_options(options) {}
|
||||
|
||||
QHexView* QHexCursor::hexView() const {
|
||||
return qobject_cast<QHexView*>(this->parent());
|
||||
}
|
||||
|
||||
QHexCursor::Mode QHexCursor::mode() const { return m_mode; }
|
||||
qint64 QHexCursor::offset() const { return this->positionToOffset(m_position); }
|
||||
|
||||
qint64 QHexCursor::address() const {
|
||||
return m_options->baseaddress + this->offset();
|
||||
}
|
||||
|
||||
quint64 QHexCursor::lineAddress() const {
|
||||
return m_options->baseaddress + (m_position.line * m_options->linelength);
|
||||
}
|
||||
|
||||
qint64 QHexCursor::selectionStartOffset() const {
|
||||
return this->positionToOffset(this->selectionStart());
|
||||
}
|
||||
|
||||
qint64 QHexCursor::selectionEndOffset() const {
|
||||
return this->positionToOffset(this->selectionEnd());
|
||||
}
|
||||
|
||||
qint64 QHexCursor::line() const { return m_position.line; }
|
||||
qint64 QHexCursor::column() const { return m_position.column; }
|
||||
|
||||
QHexPosition QHexCursor::selectionStart() const {
|
||||
if(m_position.line < m_selection.line)
|
||||
return m_position;
|
||||
|
||||
if(m_position.line == m_selection.line) {
|
||||
if(m_position.column < m_selection.column)
|
||||
return m_position;
|
||||
}
|
||||
|
||||
return m_selection;
|
||||
}
|
||||
|
||||
QHexPosition QHexCursor::selectionEnd() const {
|
||||
if(m_position.line > m_selection.line)
|
||||
return m_position;
|
||||
|
||||
if(m_position.line == m_selection.line) {
|
||||
if(m_position.column > m_selection.column)
|
||||
return m_position;
|
||||
}
|
||||
|
||||
return m_selection;
|
||||
}
|
||||
|
||||
qint64 QHexCursor::selectionLength() const {
|
||||
auto selstart = this->selectionStartOffset(),
|
||||
selend = this->selectionEndOffset();
|
||||
return selstart == selend ? 0 : selend - selstart + 1;
|
||||
}
|
||||
|
||||
QHexPosition QHexCursor::position() const { return m_position; }
|
||||
|
||||
QByteArray QHexCursor::selectedBytes() const {
|
||||
return this->hexView()->selectedBytes();
|
||||
}
|
||||
|
||||
bool QHexCursor::hasSelection() const { return m_position != m_selection; }
|
||||
|
||||
bool QHexCursor::isSelected(qint64 line, qint64 column) const {
|
||||
if(!this->hasSelection())
|
||||
return false;
|
||||
|
||||
auto selstart = this->selectionStart(), selend = this->selectionEnd();
|
||||
if(line > selstart.line && line < selend.line)
|
||||
return true;
|
||||
if(line == selstart.line && line == selend.line)
|
||||
return column >= selstart.column && column <= selend.column;
|
||||
if(line == selstart.line)
|
||||
return column >= selstart.column;
|
||||
if(line == selend.line)
|
||||
return column <= selend.column;
|
||||
return false;
|
||||
}
|
||||
|
||||
void QHexCursor::setMode(Mode m) {
|
||||
if(m_mode == m)
|
||||
return;
|
||||
m_mode = m;
|
||||
Q_EMIT modeChanged();
|
||||
}
|
||||
|
||||
void QHexCursor::switchMode() {
|
||||
switch(m_mode) {
|
||||
case Mode::Insert: this->setMode(Mode::Overwrite); break;
|
||||
case Mode::Overwrite: this->setMode(Mode::Insert); break;
|
||||
}
|
||||
}
|
||||
|
||||
void QHexCursor::move(qint64 offset) {
|
||||
this->move(this->offsetToPosition(offset));
|
||||
}
|
||||
|
||||
void QHexCursor::move(qint64 line, qint64 column) {
|
||||
return this->move({line, column});
|
||||
}
|
||||
|
||||
void QHexCursor::move(QHexPosition pos) {
|
||||
if(pos.line >= 0)
|
||||
m_selection.line = pos.line;
|
||||
if(pos.column >= 0)
|
||||
m_selection.column = pos.column;
|
||||
this->select(pos);
|
||||
}
|
||||
|
||||
void QHexCursor::select(qint64 offset) {
|
||||
this->select(this->offsetToPosition(offset));
|
||||
}
|
||||
|
||||
void QHexCursor::select(qint64 line, qint64 column) {
|
||||
this->select({line, column});
|
||||
}
|
||||
|
||||
void QHexCursor::select(QHexPosition pos) {
|
||||
if(pos.line >= 0)
|
||||
m_position.line = pos.line;
|
||||
if(pos.column >= 0)
|
||||
m_position.column = pos.column;
|
||||
Q_EMIT positionChanged();
|
||||
}
|
||||
|
||||
void QHexCursor::selectSize(qint64 length) {
|
||||
if(length > 0)
|
||||
length--;
|
||||
else if(length < 0)
|
||||
length++;
|
||||
if(length)
|
||||
this->select(this->offset() + length);
|
||||
}
|
||||
|
||||
qint64 QHexCursor::replace(const QVariant& oldvalue, const QVariant& newvalue,
|
||||
qint64 offset, QHexFindMode mode,
|
||||
unsigned int options, QHexFindDirection fd) const {
|
||||
return this->hexView()->replace(oldvalue, newvalue, offset, mode, options,
|
||||
fd);
|
||||
}
|
||||
qint64 QHexCursor::find(const QVariant& value, qint64 offset, QHexFindMode mode,
|
||||
unsigned int options, QHexFindDirection fd) const {
|
||||
return this->hexView()->find(value, offset, mode, options, fd);
|
||||
}
|
||||
|
||||
void QHexCursor::cut(bool hex) { this->hexView()->cut(hex); }
|
||||
void QHexCursor::copy(bool hex) const { this->hexView()->copy(hex); }
|
||||
void QHexCursor::paste(bool hex) { this->hexView()->paste(hex); }
|
||||
void QHexCursor::selectAll() { this->hexView()->selectAll(); }
|
||||
void QHexCursor::removeSelection() { this->hexView()->removeSelection(); }
|
||||
|
||||
void QHexCursor::clearSelection() {
|
||||
m_position = m_selection;
|
||||
Q_EMIT positionChanged();
|
||||
}
|
||||
|
||||
qint64 QHexCursor::positionToOffset(QHexPosition pos) const {
|
||||
return QHexUtils::positionToOffset(m_options, pos);
|
||||
}
|
||||
|
||||
QHexPosition QHexCursor::offsetToPosition(qint64 offset) const {
|
||||
return QHexUtils::offsetToPosition(m_options, offset);
|
||||
}
|
65
UEFITool/QHexView/src/model/qhexdelegate.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include <QHexView/model/qhexdelegate.h>
|
||||
#include <QHexView/qhexview.h>
|
||||
|
||||
QHexDelegate::QHexDelegate(QObject* parent): QObject{parent} {}
|
||||
|
||||
QString QHexDelegate::addressHeader(const QHexView* hexview) const {
|
||||
Q_UNUSED(hexview);
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString QHexDelegate::hexHeader(const QHexView* hexview) const {
|
||||
Q_UNUSED(hexview);
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString QHexDelegate::asciiHeader(const QHexView* hexview) const {
|
||||
Q_UNUSED(hexview);
|
||||
return QString();
|
||||
}
|
||||
|
||||
void QHexDelegate::renderAddress(quint64 address, QTextCharFormat& cf,
|
||||
const QHexView* hexview) const {
|
||||
Q_UNUSED(address);
|
||||
Q_UNUSED(hexview);
|
||||
Q_UNUSED(cf);
|
||||
Q_UNUSED(hexview);
|
||||
}
|
||||
|
||||
void QHexDelegate::renderHeader(QTextBlockFormat& bf,
|
||||
const QHexView* hexview) const {
|
||||
Q_UNUSED(bf);
|
||||
Q_UNUSED(hexview);
|
||||
}
|
||||
|
||||
void QHexDelegate::renderHeaderPart(const QString& s, QHexArea area,
|
||||
QTextCharFormat& cf,
|
||||
const QHexView* hexview) const {
|
||||
Q_UNUSED(s);
|
||||
Q_UNUSED(area);
|
||||
Q_UNUSED(cf);
|
||||
Q_UNUSED(hexview);
|
||||
}
|
||||
|
||||
bool QHexDelegate::render(quint64 offset, quint8 b, QTextCharFormat& outcf,
|
||||
const QHexView* hexview) const {
|
||||
Q_UNUSED(offset);
|
||||
Q_UNUSED(b);
|
||||
Q_UNUSED(outcf);
|
||||
Q_UNUSED(hexview);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QHexDelegate::paintSeparator(QPainter* painter, QLineF line,
|
||||
const QHexView* hexview) const {
|
||||
Q_UNUSED(painter);
|
||||
Q_UNUSED(line);
|
||||
Q_UNUSED(hexview);
|
||||
return false;
|
||||
}
|
||||
|
||||
void QHexDelegate::paint(QPainter* painter, const QHexView* hexview) const {
|
||||
Q_UNUSED(hexview);
|
||||
hexview->paint(painter);
|
||||
}
|
142
UEFITool/QHexView/src/model/qhexdocument.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
#include <QBuffer>
|
||||
#include <QFile>
|
||||
#include <QHexView/model/buffer/qdevicebuffer.h>
|
||||
#include <QHexView/model/buffer/qmappedfilebuffer.h>
|
||||
#include <QHexView/model/buffer/qmemorybuffer.h>
|
||||
#include <QHexView/model/commands/insertcommand.h>
|
||||
#include <QHexView/model/commands/removecommand.h>
|
||||
#include <QHexView/model/commands/replacecommand.h>
|
||||
#include <QHexView/model/qhexdocument.h>
|
||||
#include <cmath>
|
||||
|
||||
QHexDocument::QHexDocument(QHexBuffer* buffer, QObject* parent)
|
||||
: QObject(parent) {
|
||||
m_buffer = buffer;
|
||||
m_buffer->setParent(this); // Take Ownership
|
||||
|
||||
connect(&m_undostack, &QUndoStack::canUndoChanged, this,
|
||||
&QHexDocument::canUndoChanged);
|
||||
connect(&m_undostack, &QUndoStack::canRedoChanged, this,
|
||||
&QHexDocument::canRedoChanged);
|
||||
connect(&m_undostack, &QUndoStack::cleanChanged, this,
|
||||
[&](bool clean) { Q_EMIT modifiedChanged(!clean); });
|
||||
}
|
||||
|
||||
qint64 QHexDocument::indexOf(const QByteArray& ba, qint64 from) {
|
||||
return m_buffer->indexOf(ba, from);
|
||||
}
|
||||
|
||||
qint64 QHexDocument::lastIndexOf(const QByteArray& ba, qint64 from) {
|
||||
return m_buffer->lastIndexOf(ba, from);
|
||||
}
|
||||
|
||||
bool QHexDocument::accept(qint64 idx) const { return m_buffer->accept(idx); }
|
||||
bool QHexDocument::isEmpty() const { return m_buffer->isEmpty(); }
|
||||
bool QHexDocument::isModified() const { return !m_undostack.isClean(); }
|
||||
bool QHexDocument::canUndo() const { return m_undostack.canUndo(); }
|
||||
bool QHexDocument::canRedo() const { return m_undostack.canRedo(); }
|
||||
|
||||
void QHexDocument::setData(const QByteArray& ba) {
|
||||
QHexBuffer* mb = new QMemoryBuffer();
|
||||
mb->read(ba);
|
||||
this->setData(mb);
|
||||
}
|
||||
|
||||
void QHexDocument::setData(QHexBuffer* buffer) {
|
||||
if(!buffer)
|
||||
return;
|
||||
|
||||
m_undostack.clear();
|
||||
buffer->setParent(this);
|
||||
|
||||
auto* oldbuffer = m_buffer;
|
||||
m_buffer = buffer;
|
||||
if(oldbuffer)
|
||||
oldbuffer->deleteLater();
|
||||
|
||||
Q_EMIT canUndoChanged(false);
|
||||
Q_EMIT canRedoChanged(false);
|
||||
Q_EMIT changed();
|
||||
Q_EMIT reset();
|
||||
}
|
||||
|
||||
void QHexDocument::clearModified() { m_undostack.setClean(); }
|
||||
|
||||
qint64 QHexDocument::length() const {
|
||||
return m_buffer ? m_buffer->length() : 0;
|
||||
}
|
||||
|
||||
uchar QHexDocument::at(int offset) const { return m_buffer->at(offset); }
|
||||
|
||||
QHexDocument* QHexDocument::fromFile(QString filename, QObject* parent) {
|
||||
QFile f(filename);
|
||||
f.open(QFile::ReadOnly);
|
||||
return QHexDocument::fromMemory<QMemoryBuffer>(f.readAll(), parent);
|
||||
}
|
||||
|
||||
void QHexDocument::undo() {
|
||||
m_undostack.undo();
|
||||
Q_EMIT changed();
|
||||
}
|
||||
|
||||
void QHexDocument::redo() {
|
||||
m_undostack.redo();
|
||||
Q_EMIT changed();
|
||||
}
|
||||
|
||||
void QHexDocument::insert(qint64 offset, uchar b) {
|
||||
this->insert(offset, QByteArray(1, b));
|
||||
}
|
||||
|
||||
void QHexDocument::replace(qint64 offset, uchar b) {
|
||||
this->replace(offset, QByteArray(1, b));
|
||||
}
|
||||
|
||||
void QHexDocument::insert(qint64 offset, const QByteArray& data) {
|
||||
m_undostack.push(new InsertCommand(m_buffer, this, offset, data));
|
||||
|
||||
Q_EMIT changed();
|
||||
Q_EMIT dataChanged(data, offset, ChangeReason::Insert);
|
||||
}
|
||||
|
||||
void QHexDocument::replace(qint64 offset, const QByteArray& data) {
|
||||
m_undostack.push(new ReplaceCommand(m_buffer, this, offset, data));
|
||||
Q_EMIT changed();
|
||||
Q_EMIT dataChanged(data, offset, ChangeReason::Replace);
|
||||
}
|
||||
|
||||
void QHexDocument::remove(qint64 offset, int len) {
|
||||
QByteArray data = m_buffer->read(offset, len);
|
||||
|
||||
m_undostack.push(new RemoveCommand(m_buffer, this, offset, len));
|
||||
Q_EMIT changed();
|
||||
Q_EMIT dataChanged(data, offset, ChangeReason::Remove);
|
||||
}
|
||||
|
||||
QByteArray QHexDocument::read(qint64 offset, int len) const {
|
||||
return m_buffer->read(offset, len);
|
||||
}
|
||||
|
||||
bool QHexDocument::saveTo(QIODevice* device) {
|
||||
if(!device->isWritable())
|
||||
return false;
|
||||
m_buffer->write(device);
|
||||
return true;
|
||||
}
|
||||
|
||||
QHexDocument* QHexDocument::fromBuffer(QHexBuffer* buffer, QObject* parent) {
|
||||
return new QHexDocument(buffer, parent);
|
||||
}
|
||||
|
||||
QHexDocument* QHexDocument::fromLargeFile(QString filename, QObject* parent) {
|
||||
return QHexDocument::fromDevice<QDeviceBuffer>(new QFile(filename), parent);
|
||||
}
|
||||
|
||||
QHexDocument* QHexDocument::fromMappedFile(QString filename, QObject* parent) {
|
||||
return QHexDocument::fromDevice<QMappedFileBuffer>(new QFile(filename),
|
||||
parent);
|
||||
}
|
||||
|
||||
QHexDocument* QHexDocument::create(QObject* parent) {
|
||||
return QHexDocument::fromMemory<QMemoryBuffer>({}, parent);
|
||||
}
|
158
UEFITool/QHexView/src/model/qhexmetadata.cpp
Normal file
|
@ -0,0 +1,158 @@
|
|||
#include <QHexView/model/qhexcursor.h>
|
||||
#include <QHexView/model/qhexmetadata.h>
|
||||
|
||||
QHexMetadata::QHexMetadata(const QHexOptions* options, QObject* parent)
|
||||
: QObject(parent), m_options(options) {}
|
||||
|
||||
const QHexMetadataLine* QHexMetadata::find(qint64 line) const {
|
||||
auto it = m_metadata.find(line);
|
||||
return it != m_metadata.end() ? std::addressof(it.value()) : nullptr;
|
||||
}
|
||||
|
||||
QString QHexMetadata::getComment(qint64 line, qint64 column) const {
|
||||
auto* metadataline = this->find(line);
|
||||
if(!metadataline)
|
||||
return QString();
|
||||
|
||||
auto offset = QHexUtils::positionToOffset(m_options, {line, column});
|
||||
QStringList comments;
|
||||
|
||||
for(auto& mi : *metadataline) {
|
||||
if((offset < mi.begin || offset > mi.end) || mi.comment.isEmpty())
|
||||
continue;
|
||||
comments.push_back(mi.comment);
|
||||
}
|
||||
|
||||
return comments.join("\n");
|
||||
}
|
||||
|
||||
void QHexMetadata::removeMetadata(qint64 line) {
|
||||
auto it = m_metadata.find(line);
|
||||
if(it == m_metadata.end())
|
||||
return;
|
||||
|
||||
m_metadata.erase(it);
|
||||
Q_EMIT changed();
|
||||
}
|
||||
|
||||
void QHexMetadata::removeBackground(qint64 line) {
|
||||
this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool {
|
||||
if(!mi.background.isValid())
|
||||
return false;
|
||||
|
||||
if(mi.foreground.isValid() || !mi.comment.isEmpty()) {
|
||||
mi.background = QColor();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void QHexMetadata::removeForeground(qint64 line) {
|
||||
this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool {
|
||||
if(!mi.foreground.isValid())
|
||||
return false;
|
||||
|
||||
if(mi.background.isValid() || !mi.comment.isEmpty()) {
|
||||
mi.foreground = QColor();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void QHexMetadata::removeComments(qint64 line) {
|
||||
this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool {
|
||||
if(mi.comment.isEmpty())
|
||||
return false;
|
||||
|
||||
if(mi.foreground.isValid() || mi.background.isValid()) {
|
||||
mi.comment.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void QHexMetadata::unhighlight(qint64 line) {
|
||||
this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool {
|
||||
if(!mi.foreground.isValid() && !mi.background.isValid())
|
||||
return false;
|
||||
|
||||
if(!mi.comment.isEmpty()) {
|
||||
mi.foreground = QColor();
|
||||
mi.background = QColor();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void QHexMetadata::clear() {
|
||||
m_metadata.clear();
|
||||
Q_EMIT changed();
|
||||
}
|
||||
|
||||
void QHexMetadata::copy(const QHexMetadata* metadata) {
|
||||
m_metadata = metadata->m_metadata;
|
||||
}
|
||||
|
||||
void QHexMetadata::clearMetadata(qint64 line, ClearMetadataCallback&& cb) {
|
||||
auto iit = m_metadata.find(line);
|
||||
if(iit == m_metadata.end())
|
||||
return;
|
||||
|
||||
auto oldsize = iit->size();
|
||||
|
||||
for(auto it = iit->begin(); it != iit->end();) {
|
||||
if(cb(*it))
|
||||
it = iit->erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
if(iit->empty()) {
|
||||
this->removeMetadata(line);
|
||||
return;
|
||||
}
|
||||
|
||||
if(oldsize != iit->size())
|
||||
Q_EMIT changed();
|
||||
}
|
||||
|
||||
void QHexMetadata::setMetadata(const QHexMetadataItem& mi) {
|
||||
if(!m_options->linelength)
|
||||
return;
|
||||
|
||||
const qint64 firstline = mi.begin / m_options->linelength;
|
||||
const qint64 lastline = mi.end / m_options->linelength;
|
||||
bool notify = false;
|
||||
|
||||
for(auto line = firstline; line <= lastline; line++) {
|
||||
auto start = line == firstline ? mi.begin % m_options->linelength : 0;
|
||||
auto length = line == lastline
|
||||
? (mi.end % m_options->linelength) - start
|
||||
: m_options->linelength;
|
||||
if(length <= 0)
|
||||
continue;
|
||||
|
||||
notify = true;
|
||||
m_metadata[line].push_back(mi);
|
||||
}
|
||||
|
||||
if(notify)
|
||||
Q_EMIT changed();
|
||||
}
|
||||
|
||||
void QHexMetadata::invalidate() {
|
||||
auto oldmetadata = m_metadata;
|
||||
m_metadata.clear();
|
||||
|
||||
for(const QHexMetadataLine& line : oldmetadata)
|
||||
for(const QHexMetadataItem& mi : line)
|
||||
this->setMetadata(mi);
|
||||
}
|
384
UEFITool/QHexView/src/model/qhexutils.cpp
Normal file
|
@ -0,0 +1,384 @@
|
|||
#include <QDataStream>
|
||||
#include <QGlobalStatic>
|
||||
#include <QHash>
|
||||
#include <QHexView/model/qhexoptions.h>
|
||||
#include <QHexView/model/qhexutils.h>
|
||||
#include <QHexView/qhexview.h>
|
||||
#include <QList>
|
||||
#include <QtEndian>
|
||||
#include <limits>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
#define QHEXVIEW_VARIANT_EQ(x, t) ((x).metaType().id() == QMetaType::Q##t)
|
||||
#else
|
||||
#define QHEXVIEW_VARIANT_EQ(x, t) ((x).type() == QVariant::t)
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && _MSC_VER <= 1916 // v141_xp
|
||||
#include <ctype.h>
|
||||
namespace std {
|
||||
using ::tolower;
|
||||
}
|
||||
#else
|
||||
#include <cctype>
|
||||
#endif
|
||||
|
||||
namespace QHexUtils {
|
||||
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QList<char>, HEXMAP,
|
||||
({'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f'}));
|
||||
|
||||
bool isHex(char ch) {
|
||||
return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') ||
|
||||
(ch >= 'a' && ch <= 'f');
|
||||
}
|
||||
|
||||
namespace PatternUtils {
|
||||
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, WILDCARD_BYTE, ("??"))
|
||||
|
||||
bool check(QString& p, qint64& len) {
|
||||
static QHash<QString, QPair<QString, size_t>>
|
||||
processed; // Cache processed patterns
|
||||
|
||||
auto it = processed.find(p);
|
||||
|
||||
if(it != processed.end()) {
|
||||
p = it.value().first;
|
||||
len = it.value().second;
|
||||
return true;
|
||||
}
|
||||
|
||||
QString op = p; // Store unprocessed pattern
|
||||
p = p.simplified().replace(" ", "");
|
||||
if(p.isEmpty() || (p.size() % 2))
|
||||
return false;
|
||||
|
||||
int wccount = 0;
|
||||
|
||||
for(auto i = 0; i < p.size() - 2; i += 2) {
|
||||
const auto& hexb = p.mid(i, 2);
|
||||
|
||||
if(hexb == *WILDCARD_BYTE) {
|
||||
wccount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!QHexUtils::isHex(hexb.at(0).toLatin1()) ||
|
||||
!QHexUtils::isHex(hexb.at(1).toLatin1()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(wccount >= p.size())
|
||||
return false;
|
||||
len = p.size() / 2;
|
||||
processed[op] = qMakePair(p, len); // Cache processed pattern
|
||||
return true;
|
||||
}
|
||||
|
||||
bool match(const QByteArray& data, const QString& pattern) {
|
||||
for(qint64 i = 0, idx = 0; (i <= (pattern.size() - 2)); i += 2, idx++) {
|
||||
if(idx >= data.size())
|
||||
return false;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QStringView hexb = QStringView{pattern}.mid(i, 2);
|
||||
#else
|
||||
const QStringRef& hexb = pattern.midRef(i, 2);
|
||||
#endif
|
||||
|
||||
if(hexb == *WILDCARD_BYTE)
|
||||
continue;
|
||||
|
||||
bool ok = false;
|
||||
auto b = static_cast<char>(hexb.toUInt(&ok, 16));
|
||||
if(!ok || (b != data.at(idx)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace PatternUtils
|
||||
|
||||
namespace {
|
||||
|
||||
unsigned int countBits(uint val) {
|
||||
if(val <= std::numeric_limits<quint8>::max())
|
||||
return QHexFindOptions::Int8;
|
||||
if(val <= std::numeric_limits<quint16>::max())
|
||||
return QHexFindOptions::Int16;
|
||||
if(val <= std::numeric_limits<quint32>::max())
|
||||
return QHexFindOptions::Int32;
|
||||
|
||||
return QHexFindOptions::Int64;
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
qint64 findIter(qint64 startoffset, QHexFindDirection fd,
|
||||
const QHexView* hexview, Function&& f) {
|
||||
QHexDocument* hexdocument = hexview->hexDocument();
|
||||
qint64 offset = -1;
|
||||
|
||||
QHexFindDirection cfd = fd;
|
||||
if(cfd == QHexFindDirection::All)
|
||||
cfd = QHexFindDirection::Forward;
|
||||
|
||||
qint64 i = startoffset;
|
||||
|
||||
bool restartLoopOnce = true;
|
||||
|
||||
while(offset == -1 &&
|
||||
(cfd == QHexFindDirection::Backward ? (i >= 0)
|
||||
: (i < hexdocument->length()))) {
|
||||
if(!f(i, offset))
|
||||
break;
|
||||
|
||||
if(cfd == QHexFindDirection::Backward)
|
||||
i--;
|
||||
else
|
||||
i++;
|
||||
|
||||
if(fd == QHexFindDirection::All && i >= hexdocument->length() &&
|
||||
restartLoopOnce) {
|
||||
i = 0;
|
||||
restartLoopOnce = false;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
qint64 findDefault(const QByteArray& value, qint64 startoffset,
|
||||
const QHexView* hexview, unsigned int options,
|
||||
QHexFindDirection fd) {
|
||||
QHexDocument* hexdocument = hexview->hexDocument();
|
||||
if(value.size() > hexdocument->length())
|
||||
return -1;
|
||||
|
||||
return findIter(
|
||||
startoffset, fd, hexview,
|
||||
[options, value, hexdocument](qint64 idx, qint64& offset) -> bool {
|
||||
for(auto i = 0; i < value.size(); i++) {
|
||||
qint64 curroffset = idx + i;
|
||||
|
||||
if(curroffset >= hexdocument->length()) {
|
||||
offset = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
uchar ch1 = hexdocument->at(curroffset);
|
||||
uchar ch2 = value.at(i);
|
||||
|
||||
if(!(options & QHexFindOptions::CaseSensitive)) {
|
||||
ch1 = std::tolower(ch1);
|
||||
ch2 = std::tolower(ch2);
|
||||
}
|
||||
|
||||
if(ch1 != ch2)
|
||||
break;
|
||||
if(i == value.size() - 1)
|
||||
offset = idx;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
qint64 findWildcard(QString pattern, qint64 startoffset,
|
||||
const QHexView* hexview, QHexFindDirection fd,
|
||||
qint64& patternlen) {
|
||||
QHexDocument* hexdocument = hexview->hexDocument();
|
||||
if(!PatternUtils::check(pattern, patternlen) ||
|
||||
(patternlen >= hexdocument->length()))
|
||||
return -1;
|
||||
|
||||
return findIter(
|
||||
startoffset, fd, hexview,
|
||||
[hexdocument, pattern, patternlen](qint64 idx, qint64& offset) -> bool {
|
||||
if(PatternUtils::match(hexdocument->read(idx, patternlen), pattern))
|
||||
offset = idx;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
QByteArray variantToByteArray(QVariant value, QHexFindMode mode,
|
||||
unsigned int options) {
|
||||
QByteArray v;
|
||||
|
||||
switch(mode) {
|
||||
case QHexFindMode::Text:
|
||||
if(QHEXVIEW_VARIANT_EQ(value, String))
|
||||
v = value.toString().toUtf8();
|
||||
else if(QHEXVIEW_VARIANT_EQ(value, ByteArray))
|
||||
v = value.toByteArray();
|
||||
break;
|
||||
|
||||
case QHexFindMode::Hex: {
|
||||
if(QHEXVIEW_VARIANT_EQ(value, String)) {
|
||||
qint64 len = 0;
|
||||
auto s = value.toString();
|
||||
if(!PatternUtils::check(s, len))
|
||||
return {};
|
||||
|
||||
bool ok = true;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
for(auto i = 0; ok && i < s.size(); i += 2)
|
||||
v.push_back(static_cast<char>(
|
||||
QStringView{s}.mid(i, 2).toUInt(&ok, 16)));
|
||||
#else
|
||||
for(auto i = 0; ok && i < s.size(); i += 2)
|
||||
v.push_back(
|
||||
static_cast<char>(s.midRef(i, 2).toUInt(&ok, 16)));
|
||||
#endif
|
||||
|
||||
if(!ok)
|
||||
return {};
|
||||
}
|
||||
else if(QHEXVIEW_VARIANT_EQ(value, ByteArray))
|
||||
v = value.toByteArray();
|
||||
break;
|
||||
}
|
||||
|
||||
case QHexFindMode::Int: {
|
||||
bool ok = false;
|
||||
uint val = value.toUInt(&ok);
|
||||
if(!ok)
|
||||
return QByteArray{};
|
||||
|
||||
QDataStream ds(&v, QIODevice::WriteOnly);
|
||||
|
||||
if(options & QHexFindOptions::BigEndian) {
|
||||
if(options & QHexFindOptions::Int8)
|
||||
ds << qToBigEndian<quint8>(val);
|
||||
else if(options & QHexFindOptions::Int16)
|
||||
ds << qToBigEndian<quint16>(val);
|
||||
else if(options & QHexFindOptions::Int32)
|
||||
ds << qToBigEndian<quint32>(val);
|
||||
else if(options & QHexFindOptions::Int64)
|
||||
ds << qToBigEndian<quint64>(val);
|
||||
else
|
||||
return variantToByteArray(value, mode,
|
||||
options | countBits(val));
|
||||
}
|
||||
else {
|
||||
if(options & QHexFindOptions::Int8)
|
||||
ds << static_cast<quint8>(val);
|
||||
else if(options & QHexFindOptions::Int16)
|
||||
ds << static_cast<quint16>(val);
|
||||
else if(options & QHexFindOptions::Int32)
|
||||
ds << static_cast<quint32>(val);
|
||||
else if(options & QHexFindOptions::Int64)
|
||||
ds << static_cast<quint64>(val);
|
||||
else
|
||||
return variantToByteArray(value, mode,
|
||||
options | countBits(val));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case QHexFindMode::Float: {
|
||||
bool ok = false;
|
||||
QDataStream ds(&v, QIODevice::WriteOnly);
|
||||
if(options & QHexFindOptions::Float)
|
||||
ds << value.toFloat(&ok);
|
||||
else if(options & QHexFindOptions::Double)
|
||||
ds << value.toDouble(&ok);
|
||||
if(!ok)
|
||||
return {};
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QByteArray toHex(const QByteArray& ba, char sep) {
|
||||
if(ba.isEmpty()) {
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray hex(sep ? (ba.size() * 3 - 1) : (ba.size() * 2),
|
||||
Qt::Uninitialized);
|
||||
|
||||
for(auto i = 0, o = 0; i < ba.size(); i++) {
|
||||
if(sep && i)
|
||||
hex[o++] = static_cast<uchar>(sep);
|
||||
hex[o++] = HEXMAP->at((ba.at(i) & 0xf0) >> 4);
|
||||
hex[o++] = HEXMAP->at(ba.at(i) & 0x0f);
|
||||
}
|
||||
|
||||
return hex;
|
||||
}
|
||||
|
||||
QByteArray toHex(const QByteArray& ba) { return QHexUtils::toHex(ba, '\0'); }
|
||||
qint64 positionToOffset(const QHexOptions* options, QHexPosition pos) {
|
||||
return options->linelength * pos.line + pos.column;
|
||||
}
|
||||
QHexPosition offsetToPosition(const QHexOptions* options, qint64 offset) {
|
||||
return {offset / options->linelength, offset % options->linelength};
|
||||
}
|
||||
|
||||
QPair<qint64, qint64> find(const QHexView* hexview, QVariant value,
|
||||
qint64 startoffset, QHexFindMode mode,
|
||||
unsigned int options, QHexFindDirection fd) {
|
||||
qint64 offset = -1, size = 0;
|
||||
if(startoffset == -1)
|
||||
startoffset = static_cast<qint64>(hexview->offset());
|
||||
|
||||
if(mode == QHexFindMode::Hex && QHEXVIEW_VARIANT_EQ(value, String)) {
|
||||
offset = QHexUtils::findWildcard(value.toString(), startoffset, hexview,
|
||||
fd, size);
|
||||
}
|
||||
else {
|
||||
auto ba = variantToByteArray(value, mode, options);
|
||||
|
||||
if(!ba.isEmpty()) {
|
||||
offset =
|
||||
QHexUtils::findDefault(ba, startoffset, hexview, options, fd);
|
||||
size = ba.size();
|
||||
}
|
||||
else
|
||||
offset = -1;
|
||||
}
|
||||
|
||||
return {offset, offset > -1 ? size : 0};
|
||||
}
|
||||
|
||||
bool checkPattern(QString pattern) {
|
||||
qint64 len = 0;
|
||||
return PatternUtils::check(pattern, len);
|
||||
}
|
||||
|
||||
QPair<qint64, qint64> replace(const QHexView* hexview, QVariant oldvalue,
|
||||
QVariant newvalue, qint64 startoffset,
|
||||
QHexFindMode mode, unsigned int options,
|
||||
QHexFindDirection fd) {
|
||||
auto res =
|
||||
QHexUtils::find(hexview, oldvalue, startoffset, mode, options, fd);
|
||||
|
||||
if(res.first != -1 && res.second > 0) {
|
||||
QHexDocument* hexdocument = hexview->hexDocument();
|
||||
auto ba = variantToByteArray(newvalue, mode, options);
|
||||
|
||||
if(!ba.isEmpty()) {
|
||||
hexdocument->remove(res.first, res.second);
|
||||
hexdocument->insert(res.first, ba);
|
||||
res.second = ba.size();
|
||||
}
|
||||
else {
|
||||
res.first = -1;
|
||||
res.second = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace QHexUtils
|
1583
UEFITool/QHexView/src/qhexview.cpp
Normal file
276
UEFITool/ffsfinder.cpp
Normal file
|
@ -0,0 +1,276 @@
|
|||
/* ffsfinder.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#include "ffsfinder.h"
|
||||
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
#include <QRegularExpression>
|
||||
#else
|
||||
#include <QRegExp>
|
||||
#endif
|
||||
|
||||
USTATUS FfsFinder::findHexPattern(const UByteArray & hexPattern, const UINT8 mode) {
|
||||
const UModelIndex rootIndex = model->index(0, 0);
|
||||
USTATUS ret = findHexPattern(rootIndex, hexPattern, mode);
|
||||
if (ret != U_SUCCESS)
|
||||
msg(UString("Hex pattern \"") + UString(hexPattern) + UString("\" could not be found"), rootIndex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
USTATUS FfsFinder::findHexPattern(const UModelIndex & index, const UByteArray & hexPattern, const UINT8 mode)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return U_SUCCESS;
|
||||
|
||||
if (hexPattern.isEmpty())
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
// Check for "all substrings" pattern
|
||||
if (hexPattern.count('.') == hexPattern.length())
|
||||
return U_SUCCESS;
|
||||
|
||||
USTATUS ret = U_ITEM_NOT_FOUND;
|
||||
bool hasChildren = (model->rowCount(index) > 0);
|
||||
for (int i = 0; i < model->rowCount(index); i++) {
|
||||
if (U_SUCCESS == findHexPattern(index.model()->index(i, index.column(), index), hexPattern, mode))
|
||||
ret = U_SUCCESS;
|
||||
}
|
||||
|
||||
UByteArray data;
|
||||
if (hasChildren) {
|
||||
if (mode == SEARCH_MODE_HEADER)
|
||||
data = model->header(index);
|
||||
else if (mode == SEARCH_MODE_ALL)
|
||||
data = model->header(index) + model->body(index);
|
||||
}
|
||||
else {
|
||||
if (mode == SEARCH_MODE_HEADER)
|
||||
data = model->header(index);
|
||||
else if (mode == SEARCH_MODE_BODY)
|
||||
data = model->body(index);
|
||||
else
|
||||
data = model->header(index) + model->body(index);
|
||||
}
|
||||
|
||||
UString hexBody = UString(data.toHex());
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
QRegularExpression regexp = QRegularExpression(UString(hexPattern));
|
||||
regexp.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpressionMatch regexpmatch;
|
||||
|
||||
INT32 offset = (INT32)hexBody.indexOf(regexp, 0, ®expmatch);
|
||||
#else
|
||||
QRegExp regexp = QRegExp(UString(hexPattern), Qt::CaseInsensitive);
|
||||
|
||||
INT32 offset = regexp.indexIn(hexBody);
|
||||
#endif
|
||||
while (offset >= 0) {
|
||||
if (offset % 2 == 0) {
|
||||
// For patterns that cross header|body boundary, skip patterns entirely located in body, since
|
||||
// children search above has already found them.
|
||||
if (!(hasChildren && mode == SEARCH_MODE_ALL && offset/2 >= model->header(index).size())) {
|
||||
UModelIndex parentFileIndex = model->findParentOfType(index, Types::File);
|
||||
UString name = model->name(index);
|
||||
if (model->parent(index) == parentFileIndex) {
|
||||
name = model->name(parentFileIndex) + UString("/") + name;
|
||||
}
|
||||
else if (parentFileIndex.isValid()) {
|
||||
name = model->name(parentFileIndex) + UString("/.../") + name;
|
||||
}
|
||||
|
||||
msg(UString("Hex pattern \"") + UString(hexPattern)
|
||||
+ UString("\" found as \"") + hexBody.mid(offset, hexPattern.length()).toUpper()
|
||||
+ UString("\" in ") + name
|
||||
+ usprintf(" at %s-offset %02Xh", mode == SEARCH_MODE_BODY ? "body" : "header", offset / 2),
|
||||
index);
|
||||
ret = U_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
offset = (INT32)hexBody.indexOf(regexp, (qsizetype)offset + 1, ®expmatch);
|
||||
#else
|
||||
offset = regexp.indexIn(hexBody, offset + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
USTATUS FfsFinder::findGuidPattern(const UByteArray & guidPattern, const UINT8 mode) {
|
||||
const UModelIndex rootIndex = model->index(0, 0);
|
||||
USTATUS ret = findGuidPattern(rootIndex, guidPattern, mode);
|
||||
if (ret != U_SUCCESS)
|
||||
msg(UString("GUID pattern \"") + UString(guidPattern) + UString("\" could not be found"), rootIndex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
USTATUS FfsFinder::findGuidPattern(const UModelIndex & index, const UByteArray & guidPattern, const UINT8 mode)
|
||||
{
|
||||
if (guidPattern.isEmpty())
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
if (!index.isValid())
|
||||
return U_SUCCESS;
|
||||
|
||||
USTATUS ret = U_ITEM_NOT_FOUND;
|
||||
bool hasChildren = (model->rowCount(index) > 0);
|
||||
for (int i = 0; i < model->rowCount(index); i++) {
|
||||
if (U_SUCCESS == findGuidPattern(index.model()->index(i, index.column(), index), guidPattern, mode))
|
||||
ret = U_SUCCESS;
|
||||
}
|
||||
|
||||
UByteArray data;
|
||||
if (hasChildren) {
|
||||
if (mode != SEARCH_MODE_BODY)
|
||||
data = model->header(index);
|
||||
}
|
||||
else {
|
||||
if (mode == SEARCH_MODE_HEADER)
|
||||
data.append(model->header(index));
|
||||
else if (mode == SEARCH_MODE_BODY)
|
||||
data.append(model->body(index));
|
||||
else
|
||||
data.append(model->header(index)).append(model->body(index));
|
||||
}
|
||||
|
||||
UString hexBody = UString(data.toHex());
|
||||
QList<UByteArray> list = guidPattern.split('-');
|
||||
if (list.count() != 5)
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
UByteArray hexPattern;
|
||||
// Reverse first GUID block
|
||||
hexPattern.append(list.at(0).mid(6, 2));
|
||||
hexPattern.append(list.at(0).mid(4, 2));
|
||||
hexPattern.append(list.at(0).mid(2, 2));
|
||||
hexPattern.append(list.at(0).mid(0, 2));
|
||||
// Reverse second GUID block
|
||||
hexPattern.append(list.at(1).mid(2, 2));
|
||||
hexPattern.append(list.at(1).mid(0, 2));
|
||||
// Reverse third GUID block
|
||||
hexPattern.append(list.at(2).mid(2, 2));
|
||||
hexPattern.append(list.at(2).mid(0, 2));
|
||||
// Append fourth and fifth GUID blocks as is
|
||||
hexPattern.append(list.at(3)).append(list.at(4));
|
||||
|
||||
// Check for "all substrings" pattern
|
||||
if (hexPattern.count('.') == hexPattern.length())
|
||||
return U_SUCCESS;
|
||||
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
QRegularExpression regexp((QString)UString(hexPattern));
|
||||
regexp.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
|
||||
QRegularExpressionMatch regexpmatch;
|
||||
|
||||
INT32 offset = (INT32)hexBody.indexOf(regexp, 0, ®expmatch);
|
||||
#else
|
||||
QRegExp regexp(UString(hexPattern), Qt::CaseInsensitive);
|
||||
|
||||
INT32 offset = regexp.indexIn(hexBody);
|
||||
#endif
|
||||
while (offset >= 0) {
|
||||
if (offset % 2 == 0) {
|
||||
UModelIndex parentFileIndex = model->findParentOfType(index, Types::File);
|
||||
UString name = model->name(index);
|
||||
if (model->parent(index) == parentFileIndex) {
|
||||
name = model->name(parentFileIndex) + UString("/") + name;
|
||||
}
|
||||
else if (parentFileIndex.isValid()) {
|
||||
name = model->name(parentFileIndex) + UString("/.../") + name;
|
||||
}
|
||||
|
||||
msg(UString("GUID pattern \"") + UString(guidPattern)
|
||||
+ UString("\" found as \"") + hexBody.mid(offset, hexPattern.length()).toUpper()
|
||||
+ UString("\" in ") + name
|
||||
+ usprintf(" at %s-offset %02Xh", mode == SEARCH_MODE_BODY ? "body" : "header", offset / 2),
|
||||
index);
|
||||
ret = U_SUCCESS;
|
||||
}
|
||||
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
offset = (INT32)hexBody.indexOf(regexp, (qsizetype)offset + 1, ®expmatch);
|
||||
#else
|
||||
offset = regexp.indexIn(hexBody, offset + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
USTATUS FfsFinder::findTextPattern(const UString & pattern, const UINT8 mode, const bool unicode, const Qt::CaseSensitivity caseSensitive) {
|
||||
const UModelIndex rootIndex = model->index(0, 0);
|
||||
USTATUS ret = findTextPattern(rootIndex, pattern, mode, unicode, caseSensitive);
|
||||
if (ret != U_SUCCESS)
|
||||
msg((unicode ? UString("Unicode") : UString("ASCII")) + UString(" text \"")
|
||||
+ UString(pattern) + UString("\" could not be found"), rootIndex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
USTATUS FfsFinder::findTextPattern(const UModelIndex & index, const UString & pattern, const UINT8 mode, const bool unicode, const Qt::CaseSensitivity caseSensitive)
|
||||
{
|
||||
if (pattern.isEmpty())
|
||||
return U_INVALID_PARAMETER;
|
||||
|
||||
if (!index.isValid())
|
||||
return U_SUCCESS;
|
||||
|
||||
USTATUS ret = U_ITEM_NOT_FOUND;
|
||||
bool hasChildren = (model->rowCount(index) > 0);
|
||||
for (int i = 0; i < model->rowCount(index); i++) {
|
||||
if (U_SUCCESS == findTextPattern(index.model()->index(i, index.column(), index), pattern, mode, unicode, caseSensitive))
|
||||
ret = U_SUCCESS;
|
||||
}
|
||||
|
||||
UByteArray body;
|
||||
if (hasChildren) {
|
||||
if (mode != SEARCH_MODE_BODY)
|
||||
body = model->header(index);
|
||||
}
|
||||
else {
|
||||
if (mode == SEARCH_MODE_HEADER)
|
||||
body.append(model->header(index));
|
||||
else if (mode == SEARCH_MODE_BODY)
|
||||
body.append(model->body(index));
|
||||
else
|
||||
body.append(model->header(index)).append(model->body(index));
|
||||
}
|
||||
|
||||
UString data = UString::fromLatin1((const char*)body.constData(), body.length());
|
||||
|
||||
UString searchPattern;
|
||||
if (unicode)
|
||||
searchPattern = UString::fromLatin1((const char*)pattern.utf16(), pattern.length() * 2);
|
||||
else
|
||||
searchPattern = pattern;
|
||||
|
||||
int offset = -1;
|
||||
while ((offset = (int)data.indexOf(searchPattern, (int)(offset + 1), caseSensitive)) >= 0) {
|
||||
UModelIndex parentFileIndex = model->findParentOfType(index, Types::File);
|
||||
UString name = model->name(index);
|
||||
if (model->parent(index) == parentFileIndex) {
|
||||
name = model->name(parentFileIndex) + UString("/") + name;
|
||||
}
|
||||
else if (parentFileIndex.isValid()) {
|
||||
name = model->name(parentFileIndex) + UString("/.../") + name;
|
||||
}
|
||||
|
||||
msg((unicode ? UString("Unicode") : UString("ASCII")) + UString(" text \"") + UString(pattern)
|
||||
+ UString("\" found in ") + name
|
||||
+ usprintf(" at %s-offset %02Xh", mode == SEARCH_MODE_BODY ? "body" : "header", offset),
|
||||
index);
|
||||
ret = U_SUCCESS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
50
UEFITool/ffsfinder.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* fssfinder.h
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FFSFINDER_H
|
||||
#define FFSFINDER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../common/ubytearray.h"
|
||||
#include "../common/ustring.h"
|
||||
#include "../common/basetypes.h"
|
||||
#include "../common/treemodel.h"
|
||||
|
||||
class FfsFinder
|
||||
{
|
||||
public:
|
||||
FfsFinder(const TreeModel * treeModel) : model(treeModel) {}
|
||||
~FfsFinder() {}
|
||||
|
||||
std::vector<std::pair<UString, UModelIndex> > getMessages() const { return messagesVector; }
|
||||
void clearMessages() { messagesVector.clear(); }
|
||||
|
||||
USTATUS findHexPattern(const UByteArray & hexPattern, const UINT8 mode);
|
||||
USTATUS findGuidPattern(const UByteArray & guidPattern, const UINT8 mode);
|
||||
USTATUS findTextPattern(const UString & pattern, const UINT8 mode, const bool unicode, const Qt::CaseSensitivity caseSensitive);
|
||||
|
||||
private:
|
||||
const TreeModel* model;
|
||||
std::vector<std::pair<UString, UModelIndex> > messagesVector;
|
||||
|
||||
void msg(const UString & message, const UModelIndex &index = UModelIndex()) {
|
||||
messagesVector.push_back(std::pair<UString, UModelIndex>(message, index));
|
||||
}
|
||||
|
||||
USTATUS findHexPattern(const UModelIndex & index, const UByteArray & hexPattern, const UINT8 mode);
|
||||
USTATUS findGuidPattern(const UModelIndex & index, const UByteArray & guidPattern, const UINT8 mode);
|
||||
USTATUS findTextPattern(const UModelIndex & index, const UString & pattern, const UINT8 mode, const bool unicode, const Qt::CaseSensitivity caseSensitive);
|
||||
};
|
||||
|
||||
#endif // FFSFINDER_H
|
36
UEFITool/gotoaddressdialog.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* gotoaddressdialog.h
|
||||
|
||||
Copyright (c) 2018, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOTOADDRESSDIALOG_H
|
||||
#define GOTOADDRESSDIALOG_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDialog>
|
||||
#include "ui_gotoaddressdialog.h"
|
||||
class GoToAddressDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GoToAddressDialog(QWidget* parent = NULL) :
|
||||
QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint),
|
||||
ui(new Ui::GoToAddressDialog) {
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
~GoToAddressDialog() { delete ui; }
|
||||
|
||||
Ui::GoToAddressDialog* ui;
|
||||
};
|
||||
|
||||
#endif // GOTOADDRESSDIALOG_H
|
133
UEFITool/gotoaddressdialog.ui
Normal file
|
@ -0,0 +1,133 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GoToAddressDialog</class>
|
||||
<widget class="QDialog" name="GoToAddressDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>270</width>
|
||||
<height>86</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Select item at address</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Select item at address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="HexSpinBox" name="hexSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>HexSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>hexspinbox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>GoToAddressDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>182</x>
|
||||
<y>185</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>194</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>GoToAddressDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>182</x>
|
||||
<y>185</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>194</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
36
UEFITool/gotobasedialog.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* gotobasedialog.h
|
||||
|
||||
Copyright (c) 2018, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOTOBASEDIALOG_H
|
||||
#define GOTOBASEDIALOG_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDialog>
|
||||
#include "ui_gotobasedialog.h"
|
||||
class GoToBaseDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GoToBaseDialog(QWidget* parent = NULL):
|
||||
QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint),
|
||||
ui(new Ui::GoToBaseDialog) {
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
~GoToBaseDialog() {delete ui;}
|
||||
|
||||
Ui::GoToBaseDialog* ui;
|
||||
};
|
||||
|
||||
#endif // GOTOBASEDIALOG_H
|
133
UEFITool/gotobasedialog.ui
Normal file
|
@ -0,0 +1,133 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GoToBaseDialog</class>
|
||||
<widget class="QDialog" name="GoToBaseDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>270</width>
|
||||
<height>86</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Select item at base</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Select item at base:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="HexSpinBox" name="hexSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>HexSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>hexspinbox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>GoToBaseDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>182</x>
|
||||
<y>185</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>194</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>GoToBaseDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>182</x>
|
||||
<y>185</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>194</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
86
UEFITool/hexlineedit.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
/* hexlineedit.cpp
|
||||
|
||||
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#include "hexlineedit.h"
|
||||
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
#include <QRegularExpression>
|
||||
#else
|
||||
#include <QRegExp>
|
||||
#endif
|
||||
|
||||
HexLineEdit::HexLineEdit(QWidget * parent)
|
||||
:QLineEdit(parent)
|
||||
{
|
||||
m_editAsGuid = false;
|
||||
}
|
||||
|
||||
HexLineEdit::HexLineEdit(const QString & contents, QWidget * parent)
|
||||
:QLineEdit(contents, parent)
|
||||
{
|
||||
m_editAsGuid = false;
|
||||
}
|
||||
|
||||
HexLineEdit::~HexLineEdit()
|
||||
{
|
||||
}
|
||||
|
||||
void HexLineEdit::keyPressEvent(QKeyEvent * event)
|
||||
{
|
||||
QClipboard *clipboard;
|
||||
QString originalText;
|
||||
|
||||
if (m_editAsGuid && (event == QKeySequence::Delete || event->key() == Qt::Key_Backspace))
|
||||
{
|
||||
int pos = cursorPosition();
|
||||
if (event->key() == Qt::Key_Backspace && pos > 0) {
|
||||
cursorBackward(false);
|
||||
pos = cursorPosition();
|
||||
}
|
||||
|
||||
QString txt = text();
|
||||
QString selected = selectedText();
|
||||
|
||||
if (!selected.isEmpty()) {
|
||||
pos = QLineEdit::selectionStart();
|
||||
for (int i = pos; i < pos + selected.length(); i++)
|
||||
if (txt[i] != QChar('-'))
|
||||
txt[i] = QChar('.');
|
||||
}
|
||||
else {
|
||||
txt[pos] = QChar('.');
|
||||
}
|
||||
|
||||
setCursorPosition(0);
|
||||
insert(txt);
|
||||
setCursorPosition(pos);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == QKeySequence::Paste)
|
||||
{
|
||||
clipboard = QApplication::clipboard();
|
||||
originalText = clipboard->text();
|
||||
QString cleanedHex = QString(originalText).replace(QString("0x"), QString(""), Qt::CaseInsensitive);
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
cleanedHex.remove(QRegularExpression("[^a-fA-F\\d]+"));
|
||||
#else
|
||||
cleanedHex.remove(QRegExp("[^a-fA-F\\d]+"));
|
||||
#endif
|
||||
clipboard->setText(cleanedHex);
|
||||
}
|
||||
|
||||
// Call original event handler
|
||||
QLineEdit::keyPressEvent(event);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/* guidlineedit.h
|
||||
/* hexlineedit.h
|
||||
|
||||
Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
|
@ -11,26 +11,41 @@
|
|||
|
||||
*/
|
||||
|
||||
#ifndef __GUIDLINEEDIT_H__
|
||||
#define __GUIDLINEEDIT_H__
|
||||
#ifndef HEXLINEEDIT_H
|
||||
#define HEXLINEEDIT_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QLineEdit>
|
||||
#include <QKeyEvent>
|
||||
#include <QKeySequence>
|
||||
#include <QString>
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "../common/basetypes.h"
|
||||
|
||||
class GuidLineEdit : public QLineEdit
|
||||
class HexLineEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool editAsGuid READ editAsGuid WRITE setEditAsGuid)
|
||||
|
||||
public:
|
||||
GuidLineEdit(QWidget * parent = 0);
|
||||
GuidLineEdit(const QString & contents, QWidget * parent = 0);
|
||||
~GuidLineEdit();
|
||||
HexLineEdit(QWidget * parent = 0);
|
||||
HexLineEdit(const QString & contents, QWidget * parent = 0);
|
||||
~HexLineEdit();
|
||||
|
||||
void setEditAsGuid(bool editAsGuid)
|
||||
{
|
||||
m_editAsGuid = editAsGuid;
|
||||
}
|
||||
bool editAsGuid() const
|
||||
{ return m_editAsGuid; }
|
||||
|
||||
private:
|
||||
bool m_editAsGuid;
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent * event);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // HEXLINEEDIT_H
|
41
UEFITool/hexspinbox.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* hexspinbox.cpp
|
||||
|
||||
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#include "hexspinbox.h"
|
||||
#include <QDebug>
|
||||
|
||||
HexSpinBox::HexSpinBox(QWidget *parent) :
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
QSpinBox(parent), validator(QRegularExpression("0x([0-9a-fA-F]){1,8}"))
|
||||
#else
|
||||
QSpinBox(parent), validator(QRegExp("0x([0-9a-fA-F]){1,8}"))
|
||||
#endif
|
||||
{
|
||||
this->setRange(INT_MIN, INT_MAX);
|
||||
this->setPrefix("0x");
|
||||
}
|
||||
|
||||
QValidator::State HexSpinBox::validate(QString &text, int &pos) const
|
||||
{
|
||||
return validator.validate(text, pos);
|
||||
}
|
||||
|
||||
QString HexSpinBox::textFromValue(int val) const
|
||||
{
|
||||
return QString::number((uint)val, 16).toUpper();
|
||||
}
|
||||
|
||||
int HexSpinBox::valueFromText(const QString &text) const
|
||||
{
|
||||
return (int)text.toUInt(NULL, 16);
|
||||
}
|
45
UEFITool/hexspinbox.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* hexspinbox.h
|
||||
|
||||
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HEXSPINBOX_H
|
||||
#define HEXSPINBOX_H
|
||||
|
||||
#include <QSpinBox>
|
||||
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
#include <QRegularExpressionValidator>
|
||||
#else
|
||||
#include <QRegExpValidator>
|
||||
#endif
|
||||
|
||||
class HexSpinBox : public QSpinBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HexSpinBox(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
QValidator::State validate(QString &text, int &pos) const;
|
||||
int valueFromText(const QString &text) const;
|
||||
QString textFromValue(int value) const;
|
||||
|
||||
private:
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
QRegularExpressionValidator validator;
|
||||
#else
|
||||
QRegExpValidator validator;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // HEXSPINBOX_H
|
68
UEFITool/hexviewdialog.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* hexviewdialog.cpp
|
||||
|
||||
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#include "hexviewdialog.h"
|
||||
|
||||
HexViewDialog::HexViewDialog(QWidget *parent) :
|
||||
QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint),
|
||||
ui(new Ui::HexViewDialog),
|
||||
hexView(NULL)
|
||||
{
|
||||
// Create UI
|
||||
ui->setupUi(this);
|
||||
hexView = new QHexView(this);
|
||||
hexView->setReadOnly(true);
|
||||
ui->layout->addWidget(hexView);
|
||||
}
|
||||
|
||||
HexViewDialog::~HexViewDialog()
|
||||
{
|
||||
delete hexView;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void HexViewDialog::setFont(const QFont &font)
|
||||
{
|
||||
hexView->setFont(font);
|
||||
}
|
||||
|
||||
void HexViewDialog::setItem(const UModelIndex & index, HexViewType type)
|
||||
{
|
||||
const TreeModel * model = (const TreeModel*)index.model();
|
||||
UString itemName = model->name(index);
|
||||
UString itemText = model->text(index);
|
||||
|
||||
// Set hex data and dialog title
|
||||
QByteArray hexdata;
|
||||
UString dialogTitle;
|
||||
|
||||
switch (type) {
|
||||
case fullHexView:
|
||||
dialogTitle = UString("Hex view: ");
|
||||
hexdata = model->header(index) + model->body(index) + model->tail(index);
|
||||
break;
|
||||
case bodyHexView:
|
||||
dialogTitle = UString("Body hex view: ");
|
||||
hexdata = model->body(index);
|
||||
break;
|
||||
case uncompressedHexView:
|
||||
dialogTitle = UString("Uncompressed hex view: ");
|
||||
hexdata = model->uncompressedData(index);
|
||||
break;
|
||||
}
|
||||
|
||||
dialogTitle += itemText.isEmpty() ? itemName : itemName + " | " + itemText;
|
||||
setWindowTitle(dialogTitle);
|
||||
hexView->setData(hexdata);
|
||||
hexView->setFont(QApplication::font());
|
||||
}
|
44
UEFITool/hexviewdialog.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* hexviewdialog.h
|
||||
|
||||
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HEXVIEWDIALOG_H
|
||||
#define HEXVIEWDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QHexView/qhexview.h>
|
||||
#include "../common/treemodel.h"
|
||||
#include "ui_hexviewdialog.h"
|
||||
|
||||
class HexViewDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum HexViewType {
|
||||
fullHexView,
|
||||
bodyHexView,
|
||||
uncompressedHexView
|
||||
};
|
||||
|
||||
HexViewDialog(QWidget *parent = 0);
|
||||
~HexViewDialog();
|
||||
Ui::HexViewDialog* ui;
|
||||
|
||||
void setItem(const UModelIndex & index, HexViewType dataType);
|
||||
void setFont(const QFont &font);
|
||||
|
||||
private:
|
||||
QHexView * hexView;
|
||||
};
|
||||
|
||||
#endif // HEXVIEWDIALOG_H
|
36
UEFITool/hexviewdialog.ui
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>HexViewDialog</class>
|
||||
<widget class="QDialog" name="HexViewDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>640</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
BIN
UEFITool/icons/uefitool.icns
Normal file
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
BIN
UEFITool/icons/uefitool_128x128.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
UEFITool/icons/uefitool_16x16.png
Normal file
After Width: | Height: | Size: 693 B |
BIN
UEFITool/icons/uefitool_256x256.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
UEFITool/icons/uefitool_32x32.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
UEFITool/icons/uefitool_48x48.png
Normal file
After Width: | Height: | Size: 2.8 KiB |