Compare commits

..

30 commits

Author SHA1 Message Date
Alex Matrosov
3ffdae1123 0.22.1 multiple FFSv3 support fixes, thanks to @osresearch
+ multiple FFSv3 support fixes, thanks to @osresearch
+ fixed removal of FFS files with opposite EP bit value
+ disabled creation of large sections (too buggy now, will be fixed later)
2017-12-10 21:54:50 -08:00
Alex Matrosov
73019876cf add FFSv3 support with large files and large sections 2017-12-10 16:54:40 -08:00
Alex Matrosov
75225ecc28 Merge pull request #76 from mxxxc/master
Add UEFIReplace.
2017-05-06 17:24:47 -07:00
Mark
5ba63418bd Add UEFIReplace. 2017-04-14 03:24:24 +02:00
Dmytro Oleksiuk
dbeda3fc9d Merge pull request #69 from adriandumitru/Develop
Add Kaby Lake support.
2017-02-12 10:23:06 +03:00
Adrian Dumitru
b700177e4a Add Kaby Lake support. 2017-01-25 00:30:53 +02:00
Alex Matrosov
8cfd93c8eb Update patches.txt 2016-08-21 15:48:13 -07:00
Nikolaj Schlej
d54f215e67 Forgot to bump UP version 2015-11-12 09:38:14 +01:00
Nikolaj Schlej
19cc031244 UT 0.21.5 /UP 0.3.9 untested
- fixed various crashes reported in #39
- changes aren't tested yet, please don't use until #39 is fixed
2015-11-12 09:37:38 +01:00
Nikolaj Schlej
7ebbc58b9b UT 0.21.4 / UP 0.3.8
- fixed a bug introduced in 0.21.3 commit
2015-10-04 22:28:44 +02:00
Nikolaj Schlej
9d0bcd0bed Fix a compiler warning 2015-10-04 22:05:38 +02:00
Nikolaj Schlej
1ab52fde35 UT 0.21.3 / UP 0.3.7
- solved a bug with Gigabyte-specific descriptor settings (BIOS region
has size of the whole image), thanks to lordkag for #37
2015-10-04 21:58:44 +02:00
Nikolaj Schlej
388dd25093 UT 0.21.2
- fixed a bug with tailed files extraction and replacing (#35)
- fixed a bug with wrong source of padding after all Intel image regions
(#34)
2015-10-02 09:38:30 +02:00
Nikolaj Schlej
ed038c21bf Corrected #34
- padding data was a part of the image, now BIOS region
2015-10-01 08:24:35 +02:00
Nikolaj Schlej
93881e4892 Corrected EC region placement 2015-09-12 21:40:45 +02:00
Nikolaj Schlej
4e8431b169 UT 0.21.1
- added replace action for paddings
- fixed a rare visual bug (wrong image sizes in reconstructRegion
messages)
- parts of the new flash region map are defined a bit better
2015-09-12 21:01:42 +02:00
Nikolaj Schlej
9c7c94702d Replace action for paddings
- and a very small visual bugfix
2015-09-12 20:46:21 +02:00
Nikolaj Schlej
e5cf61f89a Small fixes of FLASH_DESCRIPTOR_REGION_SECTION definition 2015-09-12 19:44:59 +02:00
Nikolaj Schlej
8a14965463 Spellchecking
Corrections of issue #32
2015-09-08 08:54:42 +02:00
Nikolaj Schlej
c286459676 UP 0.3.6
- changed version number due to rebuild with engine version 0.21.0
2015-09-06 23:51:50 +02:00
Nikolaj Schlej
aa80837bf5 UT 0.21.0
- added support for new Intel descriptor type, based on
[this](http://review.coreboot.org/gitweb?p=coreboot.git;a=commit;h=1f7fd720c81755144423f2d4062c39cc651adc0a)
coreboot commit, thanks to lordkag for issue #32
- solved a bug with incorrect volume free space item placement during
volume replace, now works as expected
- solved an issue with incorrect Aptio capsule parsing introduced in
0.20.8
2015-09-06 23:46:26 +02:00
Nikolaj Schlej
9c4ddbec62 UT 0.20.8
- data after the latest region of Intel image is in tree now
- added Intel, Lenovo and Toshiba-specific capsule GUIDs to the list of
known GUIDs
- fixed bogus "File with invalid size" message while working on almost
full volumes
- pressing Cancel on "Open in new window" dialog now works as expected

Big thanks to Lordkag for spotting most of the issues (#31).
2015-08-30 10:52:19 +02:00
Nikolaj Schlej
63e5a4dd1c UT 0.20.7
- added "Open in new window..." action
2015-08-13 20:28:19 +02:00
Nikolaj Schlej
1109e44379 Create LICENSE.md 2015-08-11 18:12:12 +02:00
Nikolaj Schlej
c5fec376f7 Engine 0.20.6
- added support for recalculation of Apple-specific free space offset
value stored in volume's ZeroVector. Thanks to osxreverser for reporting
the issue #29.
- ZeroVectorCRC renamed to AppleCRC32, because it's Apple-specific after
all.
- ParsingData handling removed from old codebase, because it's only
needed for the new engine.
2015-07-05 13:28:53 +02:00
Nikolaj Schlej
d78df75de6 Update version numbers 2015-05-17 10:39:31 +02:00
Nikolaj Schlej
3013398a9d Engine 0.20.5
- raw file header was included twice during reconstruction as region
2015-05-17 10:38:04 +02:00
Nikolaj Schlej
b9b5758d2d Merge pull request #21 from cyrozap/master
Use Travis CI for build testing
2015-03-29 07:36:47 +02:00
cyrozap
351285dfbf Fixing Travis build 2015-03-28 22:20:38 -04:00
cyrozap
92c9754c02 Add Travis CI configuration 2015-03-28 22:15:06 -04:00
319 changed files with 15478 additions and 90094 deletions

View file

@ -1,418 +0,0 @@
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"

23
.gitignore vendored
View file

@ -3,7 +3,6 @@
#################
moc_*.*
ui_*.*
qrc_*.*
#################
## Qt Creator
@ -187,7 +186,6 @@ ehthumbs.db
# Folder config file
Desktop.ini
.directory
# Recycle Bin used on file shares
$RECYCLE.BIN/
@ -232,23 +230,8 @@ pip-log.txt
#############
*.o
Makefile
uefitool_plugin_import.cpp
UEFITool.app/
UEFITool/XCBuildData
UEFIDump/UEFIDump
UEFIExtract/UEFIExtract
UEFIExtract/guids.csv
UEFIFind/UEFIFind
.qmake.stash
CMakeCache.txt
CMakeFiles
cmake_install.cmake
DerivedData
*.xcodeproj
compile_commands.json
CMakeScripts
UEFITool/qrc_uefitool.cpp
XcodeQT5
XcodeQT6
*.dSYM
UEFIPatch/UEFIPatch
UEFIReplace/UEFIReplace
UEFITool

14
.travis.yml Normal file
View file

@ -0,0 +1,14 @@
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

View file

@ -1,7 +0,0 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.22)
PROJECT(UEFITool_everything)
ADD_SUBDIRECTORY(UEFIExtract)
ADD_SUBDIRECTORY(UEFIFind)
ADD_SUBDIRECTORY(UEFITool)

View file

@ -19,13 +19,13 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
static void * AllocForLzma(ISzAllocPtr p, size_t size) { (void)p; return malloc(size); }
static void FreeForLzma(ISzAllocPtr p, void *address) { (void)p; free(address); }
static void * AllocForLzma(void *p, size_t size) { (void)p; return malloc(size); }
static void FreeForLzma(void *p, void *address) { (void)p; free(address); }
static ISzAlloc SzAllocForLzma = { &AllocForLzma, &FreeForLzma };
SRes OnProgress(const ICompressProgress *p, UInt64 inSize, UInt64 outSize)
SRes OnProgress(void *p, UInt64 inSize, UInt64 outSize)
{
(void)p; (void)inSize; (void)outSize;
(void)p; (void) inSize; (void) outSize;
return SZ_OK;
}
@ -34,9 +34,9 @@ static ICompressProgress g_ProgressCallback = { &OnProgress };
STATIC
UINT64
EFIAPI
RShiftU64 (
UINT64 Operand,
UINT32 Count
RShiftU64(
UINT64 Operand,
UINT32 Count
)
{
return Operand >> Count;
@ -44,8 +44,8 @@ RShiftU64 (
VOID
SetEncodedSizeOfBuf(
UINT64 EncodedSize,
UINT8* EncodedData
UINT64 EncodedSize,
UINT8 *EncodedData
)
{
INT32 Index;
@ -58,14 +58,13 @@ SetEncodedSizeOfBuf(
}
}
USTATUS
INT32
EFIAPI
LzmaCompress (
CONST UINT8 *Source,
UINT32 SourceSize,
UINT8 *Destination,
UINT32 *DestinationSize,
UINT32 DictionarySize
LzmaCompress(
CONST UINT8 *Source,
UINT32 SourceSize,
UINT8 *Destination,
UINT32 *DestinationSize
)
{
SRes LzmaResult;
@ -73,14 +72,14 @@ LzmaCompress (
SizeT propsSize = LZMA_PROPS_SIZE;
SizeT destLen = SourceSize + SourceSize / 3 + 128;
if (*DestinationSize < (UINT32)destLen)
if (*DestinationSize < destLen)
{
*DestinationSize = (UINT32)destLen;
return EFI_BUFFER_TOO_SMALL;
*DestinationSize = destLen;
return ERR_BUFFER_TOO_SMALL;
}
LzmaEncProps_Init(&props);
props.dictSize = DictionarySize;
props.dictSize = LZMA_DICTIONARY_SIZE;
props.level = 9;
props.fb = 273;
@ -88,7 +87,7 @@ LzmaCompress (
(Byte*)((UINT8*)Destination + LZMA_HEADER_SIZE),
&destLen,
Source,
(SizeT)SourceSize,
SourceSize,
&props,
(UINT8*)Destination,
&propsSize,
@ -97,14 +96,14 @@ LzmaCompress (
&SzAllocForLzma,
&SzAllocForLzma);
*DestinationSize = (UINT32)(destLen + LZMA_HEADER_SIZE);
*DestinationSize = destLen + LZMA_HEADER_SIZE;
SetEncodedSizeOfBuf(SourceSize, Destination);
SetEncodedSizeOfBuf((UINT64)SourceSize, Destination);
if (LzmaResult == SZ_OK) {
return EFI_SUCCESS;
return ERR_SUCCESS;
}
else {
return EFI_INVALID_PARAMETER;
return ERR_INVALID_PARAMETER;
}
}

View file

@ -11,31 +11,29 @@
*/
#ifndef LZMACOMPRESS_H
#define LZMACOMPRESS_H
#ifndef __LZMACOMPRESS_H__
#define __LZMACOMPRESS_H__
#include "SDK/C/7zTypes.h"
#include "SDK/C/Types.h"
#include "../basetypes.h"
#ifdef __cplusplus
extern "C" {
#endif
#define DEFAULT_LZMA_DICTIONARY_SIZE 0x800000
#define LZMA_DICTIONARY_SIZE 0x800000
#define _LZMA_SIZE_OPT
USTATUS
INT32
EFIAPI
LzmaCompress (
const UINT8 *Source,
UINT32 SourceSize,
UINT8 *Destination,
UINT32 *DestinationSize,
UINT32 DictionarySize
LzmaCompress(
const UINT8 *Source,
UINT32 SourceSize,
UINT8 *Destination,
UINT32 *DestinationSize
);
#ifdef __cplusplus
}
#endif
#endif // LZMACOMPRESS_H
#endif

View file

@ -12,23 +12,23 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include "LzmaDecompress.h"
#include "SDK/C/7zTypes.h"
#include "SDK/C/Types.h"
#include "SDK/C/7zVersion.h"
#include <stdlib.h>
UINT64
EFIAPI
LShiftU64 (
UINT64 Operand,
UINT32 Count
)
LShiftU64(
UINT64 Operand,
UINT32 Count
)
{
return Operand << Count;
}
static void * AllocForLzma(ISzAllocPtr p, size_t size) { (void)p; return malloc(size); }
static void FreeForLzma(ISzAllocPtr p, void *address) { (void)p; free(address); }
static void * AllocForLzma(void *p, size_t size) { (void)p; return malloc(size); }
static void FreeForLzma(void *p, void *address) { (void)p; free(address); }
static ISzAlloc SzAllocForLzma = { &AllocForLzma, &FreeForLzma };
/*
@ -39,12 +39,12 @@ Get the size of the uncompressed buffer by parsing EncodeData header.
@return The size of the uncompressed buffer.
*/
UINT64
GetDecodedSizeOfBuf (
UINT8 *EncodedData
)
GetDecodedSizeOfBuf(
UINT8 *EncodedData
)
{
UINT64 DecodedSize;
INT32 Index;
INT32 Index;
// Parse header
DecodedSize = 0;
@ -85,27 +85,22 @@ DestinationSize and the size of the scratch
buffer was returned ScratchSize.
*/
USTATUS
INT32
EFIAPI
LzmaGetInfo (
CONST VOID *Source,
UINT32 SourceSize,
UINT32 *DestinationSize
)
LzmaGetInfo(
CONST VOID *Source,
UINT32 SourceSize,
UINT32 *DestinationSize
)
{
UINT64 DecodedSize;
ASSERT(SourceSize >= LZMA_HEADER_SIZE);
(void)SourceSize;
UInt64 DecodedSize;
ASSERT(SourceSize >= LZMA_HEADER_SIZE); (void)SourceSize;
DecodedSize = GetDecodedSizeOfBuf((UINT8*)Source);
if (DecodedSize <= UINT32_MAX) {
*DestinationSize = (UINT32)DecodedSize;
return U_SUCCESS;
}
else {
return U_INVALID_PARAMETER;
}
*DestinationSize = (UINT32)DecodedSize;
return ERR_SUCCESS;
}
/*
@ -127,13 +122,13 @@ the uncompressed buffer is returned Destination.
The source buffer specified by Source is corrupted
(not a valid compressed format).
*/
USTATUS
INT32
EFIAPI
LzmaDecompress (
CONST VOID *Source,
UINT32 SourceSize,
VOID *Destination
)
LzmaDecompress(
CONST VOID *Source,
UINT32 SourceSize,
VOID *Destination
)
{
SRes LzmaResult;
ELzmaStatus Status;
@ -156,9 +151,9 @@ LzmaDecompress (
);
if (LzmaResult == SZ_OK) {
return U_SUCCESS;
return ERR_SUCCESS;
}
else {
return U_INVALID_PARAMETER;
return ERR_INVALID_PARAMETER;
}
}

View file

@ -11,12 +11,11 @@
*/
#ifndef LZMADECOMPRESS_H
#define LZMADECOMPRESS_H
#ifndef __LZMADECOMPRESS_H__
#define __LZMADECOMPRESS_H__
#include "../basetypes.h"
#include "SDK/C/LzmaDec.h"
#include "SDK/C/Bra.h"
#ifdef __cplusplus
extern "C" {
@ -24,6 +23,13 @@ extern "C" {
#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
UINT64
EFIAPI
LShiftU64(
UINT64 Operand,
UINT32 Count
);
/*
Given a Lzma compressed source buffer, this function retrieves the size of
the uncompressed buffer and the size of the scratch buffer required
@ -51,12 +57,12 @@ extern "C" {
buffer was returned ScratchSize.
*/
USTATUS
INT32
EFIAPI
LzmaGetInfo (
CONST VOID *Source,
UINT32 SourceSize,
UINT32 *DestinationSize
LzmaGetInfo(
const VOID *Source,
UINT32 SourceSize,
UINT32 *DestinationSize
);
/*
@ -78,16 +84,15 @@ extern "C" {
The source buffer specified by Source is corrupted
(not a valid compressed format).
*/
USTATUS
INT32
EFIAPI
LzmaDecompress (
CONST VOID *Source,
UINT32 SourceSize,
VOID *Destination
LzmaDecompress(
const VOID *Source,
UINT32 SourceSize,
VOID *Destination
);
#ifdef __cplusplus
}
#endif
#endif // LZMADECOMPRESS_H
#endif

7
LZMA/SDK/C/7zVersion.h Normal file
View file

@ -0,0 +1,7 @@
#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

68
LZMA/SDK/C/Bra.h Normal file
View file

@ -0,0 +1,68 @@
/* 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

85
LZMA/SDK/C/Bra86.c Normal file
View file

@ -0,0 +1,85 @@
/* 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;
}

155
LZMA/SDK/C/CpuArch.h Normal file
View file

@ -0,0 +1,155 @@
/* 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

754
LZMA/SDK/C/LzFind.c Normal file
View file

@ -0,0 +1,754 @@
/* 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;
}
}

115
LZMA/SDK/C/LzFind.h Normal file
View file

@ -0,0 +1,115 @@
/* 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

54
LZMA/SDK/C/LzHash.h Normal file
View file

@ -0,0 +1,54 @@
/* 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

987
LZMA/SDK/C/LzmaDec.c Normal file
View file

@ -0,0 +1,987 @@
/* 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;
}

View file

@ -1,36 +1,33 @@
/* LzmaDec.h -- LZMA Decoder
2023-04-02 : Igor Pavlov : Public domain */
2009-02-07 : Igor Pavlov : Public domain */
#ifndef ZIP7_INC_LZMA_DEC_H
#define ZIP7_INC_LZMA_DEC_H
#ifndef __LZMA_DEC_H
#define __LZMA_DEC_H
#include "7zTypes.h"
#include "Types.h"
EXTERN_C_BEGIN
#ifdef __cplusplus
extern "C" {
#endif
/* #define Z7_LZMA_PROB32 */
/* Z7_LZMA_PROB32 can increase the speed on some CPUs,
/* #define _LZMA_PROB32 */
/* _LZMA_PROB32 can increase the speed on some CPUs,
but memory usage for CLzmaDec::probs will be doubled in that case */
typedef
#ifdef Z7_LZMA_PROB32
UInt32
#ifdef _LZMA_PROB32
#define CLzmaProb UInt32
#else
UInt16
#define CLzmaProb UInt16
#endif
CLzmaProb;
/* ---------- LZMA Properties ---------- */
#define LZMA_PROPS_SIZE 5
typedef struct
typedef struct _CLzmaProps
{
Byte lc;
Byte lp;
Byte pb;
Byte _pad_;
unsigned lc, lp, pb;
UInt32 dicSize;
} CLzmaProps;
@ -52,35 +49,32 @@ SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
typedef struct
{
/* Don't change this structure. ASM code can use it. */
CLzmaProps prop;
CLzmaProb *probs;
CLzmaProb *probs_1664;
Byte *dic;
SizeT dicBufSize;
SizeT dicPos;
const Byte *buf;
UInt32 range;
UInt32 code;
UInt32 range, code;
SizeT dicPos;
SizeT dicBufSize;
UInt32 processedPos;
UInt32 checkDicSize;
unsigned state;
UInt32 reps[4];
UInt32 state;
UInt32 remainLen;
unsigned remainLen;
int needFlush;
int needInitState;
UInt32 numProbs;
unsigned tempBufSize;
Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
} CLzmaDec;
#define LzmaDec_CONSTRUCT(p) { (p)->dic = NULL; (p)->probs = NULL; }
#define LzmaDec_Construct(p) LzmaDec_CONSTRUCT(p)
#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
void LzmaDec_Init(CLzmaDec *p);
/* There are two types of LZMA streams:
- Stream with end mark. That end mark adds about 6 bytes to compressed size.
- Stream without end mark. You must know exact uncompressed size to decompress such stream. */
0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
typedef enum
{
@ -137,11 +131,11 @@ LzmaDec_Allocate* can return:
SZ_ERROR_UNSUPPORTED - Unsupported properties
*/
SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc);
SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc);
SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
/* ---------- Dictionary Interface ---------- */
@ -150,7 +144,7 @@ void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc);
You must work with CLzmaDec variables directly in this interface.
STEPS:
LzmaDec_Construct()
LzmaDec_Constr()
LzmaDec_Allocate()
for (each new stream)
{
@ -182,7 +176,6 @@ Returns:
LZMA_STATUS_NEEDS_MORE_INPUT
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
SZ_ERROR_DATA - Data error
SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure
*/
SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
@ -225,13 +218,14 @@ Returns:
SZ_ERROR_MEM - Memory allocation error
SZ_ERROR_UNSUPPORTED - Unsupported properties
SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure
*/
SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
ELzmaStatus *status, ISzAllocPtr alloc);
ELzmaStatus *status, ISzAlloc *alloc);
EXTERN_C_END
#ifdef __cplusplus
}
#endif
#endif

2248
LZMA/SDK/C/LzmaEnc.c Normal file

File diff suppressed because it is too large Load diff

80
LZMA/SDK/C/LzmaEnc.h Normal file
View file

@ -0,0 +1,80 @@
/* 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

256
LZMA/SDK/C/Types.h Normal file
View file

@ -0,0 +1,256 @@
/* 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

31
LZMA/UefiLzma.h Normal file
View file

@ -0,0 +1,31 @@
/* 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__

View file

@ -1,65 +0,0 @@
# UEFITool
UEFITool is a viewer and editor of firmware images conforming to UEFI Platform Interface (PI) Specifications.
![UEFITool icon](https://raw.githubusercontent.com/LongSoft/UEFITool/new_engine/UEFITool/icons/uefitool_64x64.png "UEFITool icon")
![CI Status](https://github.com/LongSoft/UEFITool/actions/workflows/main.yml/badge.svg?branch=new_engine) [![Scan Status](https://scan.coverity.com/projects/17209/badge.svg?flat=1)](https://scan.coverity.com/projects/17209) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=LongSoft_UEFITool&metric=alert_status)](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 Normal file
View file

@ -0,0 +1,44 @@
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.

View file

@ -69,15 +69,18 @@ PutDword(
STATIC
EFI_STATUS
AllocateMemory (VOID);
AllocateMemory (
);
STATIC
VOID
FreeMemory (VOID);
FreeMemory (
);
STATIC
VOID
InitSlide (VOID);
InitSlide (
);
STATIC
NODE
@ -102,23 +105,28 @@ Split (
STATIC
VOID
InsertNode (VOID);
InsertNode (
);
STATIC
VOID
DeleteNode (VOID);
DeleteNode (
);
STATIC
VOID
GetNextMatch (VOID);
GetNextMatch (
);
STATIC
EFI_STATUS
Encode (VOID);
Encode (
);
STATIC
VOID
CountTFreq (VOID);
CountTFreq (
);
STATIC
VOID
@ -130,7 +138,8 @@ WritePTLen (
STATIC
VOID
WriteCLen (VOID);
WriteCLen (
);
STATIC
VOID
@ -146,7 +155,8 @@ EncodeP (
STATIC
VOID
SendBlock (VOID);
SendBlock (
);
STATIC
VOID
@ -157,15 +167,18 @@ Output (
STATIC
VOID
HufEncodeStart (VOID);
HufEncodeStart (
);
STATIC
VOID
HufEncodeEnd (VOID);
HufEncodeEnd (
);
STATIC
VOID
MakeCrcTable (VOID);
MakeCrcTable (
);
STATIC
VOID
@ -183,7 +196,8 @@ FreadCrc (
STATIC
VOID
InitPutBits (VOID);
InitPutBits (
);
STATIC
VOID
@ -492,23 +506,16 @@ Returns:
UINT32 i;
mText = malloc (WNDSIZ * 2 + MAXMATCH);
if (!mText) return EFI_OUT_OF_RESOURCES;
for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) {
mText[i] = 0;
}
mLevel = malloc((WNDSIZ + UINT8_MAX + 1) * sizeof(*mLevel));
if (!mLevel) return EFI_OUT_OF_RESOURCES;
mChildCount = malloc((WNDSIZ + UINT8_MAX + 1) * sizeof(*mChildCount));
if (!mChildCount) return EFI_OUT_OF_RESOURCES;
mPosition = malloc((WNDSIZ + UINT8_MAX + 1) * sizeof(*mPosition));
if (!mPosition) return EFI_OUT_OF_RESOURCES;
mParent = malloc(WNDSIZ * 2 * sizeof(*mParent));
if (!mParent) return EFI_OUT_OF_RESOURCES;
mPrev = malloc(WNDSIZ * 2 * sizeof(*mPrev));
if (!mPrev) return EFI_OUT_OF_RESOURCES;
mNext = malloc((MAX_HASH_VAL + 1) * sizeof(*mNext));
if (!mNext) return EFI_OUT_OF_RESOURCES;
mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mLevel));
mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mChildCount));
mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mPosition));
mParent = malloc (WNDSIZ * 2 * sizeof(*mParent));
mPrev = malloc (WNDSIZ * 2 * sizeof(*mPrev));
mNext = malloc ((MAX_HASH_VAL + 1) * sizeof(*mNext));
mBufSiz = 16 * 1024U;
while ((mBuf = malloc(mBufSiz)) == NULL) {
@ -536,14 +543,39 @@ Returns: (VOID)
--*/
{
if (mText) {
free (mText);
}
if (mLevel) {
free (mLevel);
}
if (mChildCount) {
free (mChildCount);
}
if (mPosition) {
free (mPosition);
}
if (mParent) {
free (mParent);
}
if (mPrev) {
free (mPrev);
}
if (mNext) {
free (mNext);
}
if (mBuf) {
free (mBuf);
}
return;
}
@ -1559,7 +1591,7 @@ Returns: (VOID)
INT32 i;
UINT16 Start[18];
memset(Start, 0, sizeof(Start));
Start[1] = 0;
for (i = 1; i <= 16; i++) {
Start[i + 1] = (UINT16)((Start[i] + mLenCnt[i]) << 1);
}

View file

@ -20,8 +20,8 @@ Header file for compression routine.
*/
#ifndef EFITIANOCOMPRESS_H
#define EFITIANOCOMPRESS_H
#ifndef _EFITIANOCOMPRESS_H_
#define _EFITIANOCOMPRESS_H_
#include <string.h>
#include <stdlib.h>
@ -56,20 +56,22 @@ extern "C" {
--*/
EFI_STATUS
TianoCompress (
IN CONST VOID *SrcBuffer,
IN UINT32 SrcSize,
IN VOID *DstBuffer,
IN OUT UINT32 *DstSize
);
TianoCompress(
CONST VOID *SrcBuffer,
UINT32 SrcSize,
VOID *DstBuffer,
UINT32 *DstSize
)
;
EFI_STATUS
TianoCompressLegacy(
CONST VOID *SrcBuffer,
UINT32 SrcSize,
VOID *DstBuffer,
UINT32 *DstSize
);
CONST VOID *SrcBuffer,
UINT32 SrcSize,
VOID *DstBuffer,
UINT32 *DstSize
)
;
/*++
Routine Description:
@ -94,22 +96,23 @@ extern "C" {
--*/
EFI_STATUS
EfiCompress (
IN CONST VOID *SrcBuffer,
IN UINT32 SrcSize,
IN VOID *DstBuffer,
IN OUT UINT32 *DstSize
);
EfiCompress(
CONST VOID *SrcBuffer,
UINT32 SrcSize,
VOID *DstBuffer,
UINT32 *DstSize
)
;
EFI_STATUS
EfiCompressLegacy(
CONST VOID *SrcBuffer,
UINT32 SrcSize,
VOID *DstBuffer,
UINT32 *DstSize
);
CONST VOID *SrcBuffer,
UINT32 SrcSize,
VOID *DstBuffer,
UINT32 *DstSize
)
;
#ifdef __cplusplus
}
#endif
#endif // EFITIANOCOMPRESS_H
#endif

View file

@ -529,24 +529,17 @@ STATIC
{
UINT32 Index;
mText = malloc (WNDSIZ * 2 + MAXMATCH);
if (!mText) return EFI_OUT_OF_RESOURCES;
mText = malloc (WNDSIZ * 2 + MAXMATCH);
for (Index = 0; Index < WNDSIZ * 2 + MAXMATCH; Index++) {
mText[Index] = 0;
}
mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mLevel));
if (!mLevel) return EFI_OUT_OF_RESOURCES;
mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mChildCount));
if (!mChildCount) return EFI_OUT_OF_RESOURCES;
mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mPosition));
if (!mPosition) return EFI_OUT_OF_RESOURCES;
mParent = malloc (WNDSIZ * 2 * sizeof (*mParent));
if (!mParent) return EFI_OUT_OF_RESOURCES;
mPrev = malloc (WNDSIZ * 2 * sizeof (*mPrev));
if (!mPrev) return EFI_OUT_OF_RESOURCES;
mNext = malloc ((MAX_HASH_VAL + 1) * sizeof (*mNext));
if (!mNext) return EFI_OUT_OF_RESOURCES;
mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mLevel));
mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mChildCount));
mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mPosition));
mParent = malloc (WNDSIZ * 2 * sizeof (*mParent));
mPrev = malloc (WNDSIZ * 2 * sizeof (*mPrev));
mNext = malloc ((MAX_HASH_VAL + 1) * sizeof (*mNext));
mBufSiz = BLKSIZ;
mBuf = malloc (mBufSiz);
@ -580,14 +573,39 @@ VOID
--*/
{
if (mText != NULL) {
free (mText);
}
if (mLevel != NULL) {
free (mLevel);
}
if (mChildCount != NULL) {
free (mChildCount);
}
if (mPosition != NULL) {
free (mPosition);
}
if (mParent != NULL) {
free (mParent);
}
if (mPrev != NULL) {
free (mPrev);
}
if (mNext != NULL) {
free (mNext);
}
if (mBuf != NULL) {
free (mBuf);
}
return ;
}
STATIC

998
Tiano/EfiTianoDecompress.c Normal file
View file

@ -0,0 +1,998 @@
/*++ 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
);
}

141
Tiano/EfiTianoDecompress.h Normal file
View file

@ -0,0 +1,141 @@
/* 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

View file

@ -1,92 +0,0 @@
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
)

View file

@ -1,231 +0,0 @@
/* 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;
}

View file

@ -1,55 +0,0 @@
/* 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

View file

@ -1,17 +0,0 @@
executable(
'UEFIExtract',
sources: [
'uefiextract_main.cpp',
'ffsdumper.cpp',
'uefidump.cpp',
],
link_with: [
lzma,
bstrlib,
uefitoolcommon,
],
dependencies: [
zlib,
],
install: true,
)

View file

@ -1,151 +0,0 @@
/* 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;
}

View file

@ -1,43 +0,0 @@
/* 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

View file

@ -0,0 +1,49 @@
/* 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);
}

43
UEFIExtract/uefiextract.h Normal file
View file

@ -0,0 +1,43 @@
/* 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

View file

@ -1,8 +0,0 @@
<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>

View file

@ -0,0 +1,43 @@
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

View file

@ -1,219 +1,60 @@
/* uefiextract_main.cpp
Copyright (c) 2018, LongSoft. 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
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 <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;
}
#include "uefiextract.h"
int main(int argc, char *argv[])
{
initGuidDatabase("guids.csv");
QCoreApplication a(argc, argv);
a.setOrganizationName("CodeRush");
a.setOrganizationDomain("coderush.me");
a.setApplicationName("UEFIExtract");
if (argc <= 1) {
print_usage();
return 1;
}
UEFIExtract w;
UINT8 result = ERR_SUCCESS;
UINT32 returned = 0;
// 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();
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;
}
}
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;
return 1;
}
}

View file

@ -1,82 +0,0 @@
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
)

View file

@ -1,16 +0,0 @@
executable(
'UEFIFind',
sources: [
'uefifind_main.cpp',
'uefifind.cpp',
],
link_with: [
lzma,
bstrlib,
uefitoolcommon,
],
dependencies: [
zlib,
],
install: true,
)

View file

@ -1,6 +1,6 @@
/* uefifind.cpp
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
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
@ -12,137 +12,149 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include "uefifind.h"
#include <fstream>
#include <set>
UEFIFind::UEFIFind()
UEFIFind::UEFIFind(QObject *parent) :
QObject(parent)
{
model = new TreeModel();
ffsParser = new FfsParser(model);
ffsEngine = new FfsEngine(this);
model = ffsEngine->treeModel();
initDone = false;
}
UEFIFind::~UEFIFind()
{
delete ffsParser;
delete model;
model = NULL;
delete ffsEngine;
}
USTATUS UEFIFind::init(const UString & path)
UINT8 UEFIFind::init(const QString & path)
{
UByteArray buffer;
if (false == readFileIntoBuffer(path, buffer))
return U_FILE_OPEN;
UINT8 result;
USTATUS result = ffsParser->parse(buffer);
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();
result = ffsEngine->parseImageFile(buffer);
if (result)
return result;
initDone = true;
return U_SUCCESS;
return ERR_SUCCESS;
}
USTATUS UEFIFind::findFileRecursive(const UModelIndex index, const UString & hexPattern, const UINT8 mode, std::set<std::pair<UModelIndex, UModelIndex> > & files)
QString UEFIFind::guidToQString(const UINT8* guid)
{
if (!index.isValid())
return U_SUCCESS;
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 (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;
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);
}
USTATUS UEFIFind::find(const UINT8 mode, const bool count, const UString & hexPattern, UString & result)
UINT8 UEFIFind::find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result)
{
UModelIndex root = model->index(0, 0);
std::set<std::pair<UModelIndex, UModelIndex> > files;
QModelIndex root = model->index(0, 0);
QSet<QPair<QModelIndex, QModelIndex> > files;
result.clear();
USTATUS returned = findFileRecursive(root, hexPattern, mode, files);
UINT8 returned = findFileRecursive(root, hexPattern, mode, files);
if (returned)
return returned;
if (count) {
if (!files.empty())
result += usprintf("%lu\n", files.size());
return U_SUCCESS;
if (files.count())
result.append(QString("%1\n").arg(files.count()));
return ERR_SUCCESS;
}
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()));
QPair<QModelIndex, QModelIndex> indexes;
Q_FOREACH(indexes, files) {
QByteArray data = model->header(indexes.first).left(16);
result.append(guidToQString((const UINT8*)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);
result += UString(" ") + (guidToUString(readUnaligned((const EFI_GUID*)(data.constData() + sizeof(EFI_COMMON_SECTION_HEADER)))));
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)));
}
result += UString("\n");
result.append("\n");
}
return U_SUCCESS;
return ERR_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;
}

View file

@ -1,6 +1,6 @@
/* uefifind.h
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
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
@ -11,34 +11,42 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef UEFIFIND_H
#define UEFIFIND_H
#ifndef __UEFIFIND_H__
#define __UEFIFIND_H__
#include <iterator>
#include <set>
#include <QObject>
#include <QByteArray>
#include <QString>
#include <QDir>
#include <QFileInfo>
#include <QPair>
#include <QSet>
#include <QString>
#include <QUuid>
#include "../common/basetypes.h"
#include "../common/ustring.h"
#include "../common/filesystem.h"
#include "../common/ffsparser.h"
#include "../common/ffs.h"
#include "../common/utility.h"
#include "../basetypes.h"
#include "../ffsengine.h"
#include "../ffs.h"
class UEFIFind
class UEFIFind : public QObject
{
Q_OBJECT
public:
explicit UEFIFind();
explicit UEFIFind(QObject *parent = 0);
~UEFIFind();
USTATUS init(const UString & path);
USTATUS find(const UINT8 mode, const bool count, const UString & hexPattern, UString & result);
UINT8 init(const QString & path);
UINT8 find(const UINT8 mode, const bool count, const QString & hexPattern, QString & result);
private:
USTATUS findFileRecursive(const UModelIndex index, const UString & hexPattern, const UINT8 mode, std::set<std::pair<UModelIndex, UModelIndex> > & files);
UINT8 findFileRecursive(const QModelIndex index, const QString & hexPattern, const UINT8 mode, QSet<QPair<QModelIndex, QModelIndex> > & files);
QString guidToQString(const UINT8* guid);
FfsParser* ffsParser;
FfsEngine* ffsEngine;
TreeModel* model;
QFileInfo fileInfo;
bool initDone;
};
#endif // UEFIFIND_H
#endif

View file

@ -1,8 +0,0 @@
<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>

43
UEFIFind/uefifind.pro Normal file
View file

@ -0,0 +1,43 @@
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

View file

@ -1,6 +1,6 @@
/* uefifind_main.cpp
Copyright (c) 2018, LongSoft. 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
@ -10,183 +10,63 @@ 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[])
{
UEFIFind w;
USTATUS result;
QCoreApplication a(argc, argv);
a.setOrganizationName("CodeRush");
a.setOrganizationDomain("coderush.me");
a.setApplicationName("UEFIFind");
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];
UEFIFind w;
UINT8 result;
if (a.arguments().length() == 5) {
result = w.init(a.arguments().at(4));
if (result)
return result;
// Get search mode
UINT8 mode;
if (modeArg == UString("header"))
if (a.arguments().at(1) == QString("header"))
mode = SEARCH_MODE_HEADER;
else if (modeArg == UString("body"))
else if (a.arguments().at(1) == QString("body"))
mode = SEARCH_MODE_BODY;
else if (modeArg == UString("all"))
else if (a.arguments().at(1) == QString("all"))
mode = SEARCH_MODE_ALL;
else
return U_INVALID_PARAMETER;
return ERR_INVALID_PARAMETER;
// Get result type
bool count;
if (subModeArg == UString("list"))
if (a.arguments().at(2) == QString("list"))
count = false;
else if (subModeArg == UString("count"))
else if (a.arguments().at(2) == QString("count"))
count = true;
else
return U_INVALID_PARAMETER;
// Parse input file
result = w.init(inputArg);
if (result)
return result;
return ERR_INVALID_PARAMETER;
// Go find the supplied pattern
UString found;
result = w.find(mode, count, patternArg, found);
QString found;
result = w.find(mode, count, a.arguments().at(3), found);
if (result)
return result;
// Nothing is found
// Nothing was found
if (found.isEmpty())
return U_ITEM_NOT_FOUND;
return ERR_ITEM_NOT_FOUND;
// Print result
std::cout << found.toLocal8Bit();
return U_SUCCESS;
std::cout << found.toStdString();
return ERR_SUCCESS;
}
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;
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;
}
print_usage();
return U_INVALID_PARAMETER;
}

52
UEFIPatch/patches.txt Normal file
View file

@ -0,0 +1,52 @@
# 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
# PpmInitialize | Broadwell-E
3FFCAE95-23CF-4967-94F5-16352F68E43B 10 P:0FBA6C24400F:0FBA7424400F
# SiInit | Skylake
299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 10 P:75080D00800000:EB080D00800000
299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 12 P:75080D00800000:EB080D00800000
# SiInit | Kaby Lake
299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 10 P:81E10080000033C1:9090909090909090
299D6F8B-2EC9-4E40-9EC6-DDAA7EBF5FD9 12 P:81E10080000033C1:9090909090909090

149
UEFIPatch/uefipatch.cpp Normal file
View file

@ -0,0 +1,149 @@
/* 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;
}

45
UEFIPatch/uefipatch.h Normal file
View file

@ -0,0 +1,45 @@
/* 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

43
UEFIPatch/uefipatch.pro Normal file
View file

@ -0,0 +1,43 @@
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

View file

@ -0,0 +1,76 @@
/* uefipatch_main.cpp
Copyright (c) 2017, 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 "uefipatch.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
a.setOrganizationName("LongSoft");
a.setOrganizationDomain("longsoft.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.11 - 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;
}

108
UEFIReplace/uefireplace.cpp Normal file
View file

@ -0,0 +1,108 @@
/* uefireplace.cpp
Copyright (c) 2017, mxxxc. 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 "uefireplace.h"
UEFIReplace::UEFIReplace(QObject *parent) :
QObject(parent)
{
ffsEngine = new FfsEngine(this);
model = ffsEngine->treeModel();
}
UEFIReplace::~UEFIReplace()
{
delete ffsEngine;
}
UINT8 UEFIReplace::replace(QString inPath, const QByteArray & guid, const UINT8 sectionType, const QString contentPath)
{
QFileInfo fileInfo = QFileInfo(inPath);
if (!fileInfo.exists())
return ERR_FILE_OPEN;
fileInfo = QFileInfo(contentPath);
if (!fileInfo.exists())
return ERR_FILE_OPEN;
QFile inputFile;
inputFile.setFileName(inPath);
if (!inputFile.open(QFile::ReadOnly))
return ERR_FILE_READ;
QByteArray buffer = inputFile.readAll();
inputFile.close();
UINT8 result = ffsEngine->parseImageFile(buffer);
if (result)
return result;
QFile contentFile;
contentFile.setFileName(contentPath);
if (!contentFile.open(QFile::ReadOnly))
return ERR_FILE_READ;
QByteArray contents = contentFile.readAll();
contentFile.close();
result = replaceInFile(model->index(0, 0), guid, sectionType, contents);
if (result)
return result;
QByteArray reconstructed;
result = ffsEngine->reconstructImageFile(reconstructed);
if (result)
return result;
if (reconstructed == buffer)
return ERR_NOTHING_TO_PATCH;
QFile outputFile;
outputFile.setFileName(inPath.append(".patched"));
if (!outputFile.open(QFile::WriteOnly))
return ERR_FILE_WRITE;
outputFile.resize(0);
outputFile.write(reconstructed);
outputFile.close();
return ERR_SUCCESS;
}
UINT8 UEFIReplace::replaceInFile(const QModelIndex & index, const QByteArray & guid, const UINT8 sectionType, const QByteArray & newData)
{
if (!model || !index.isValid())
return ERR_INVALID_PARAMETER;
if (model->subtype(index) == sectionType) {
QModelIndex fileIndex = model->findParentOfType(index, Types::File);
QByteArray fileGuid = model->header(fileIndex).left(sizeof(EFI_GUID));
if (fileGuid == guid) {
return ffsEngine->replace(index, newData, REPLACE_MODE_BODY);
}
}
bool patched = false;
if (model->rowCount(index) > 0) {
for (int i = 0; i < model->rowCount(index); i++) {
UINT8 result = replaceInFile(index.child(i, 0), guid, sectionType, newData);
if (!result) {
patched = true;
break;
} else if (result != ERR_NOTHING_TO_PATCH)
return result;
}
}
return patched ? ERR_SUCCESS : ERR_NOTHING_TO_PATCH;
}

41
UEFIReplace/uefireplace.h Normal file
View file

@ -0,0 +1,41 @@
/* uefireplace.h
Copyright (c) 2017, mxxxc. 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 __UEFIREPLACE_H__
#define __UEFIREPLACE_H__
#include <QObject>
#include <QByteArray>
#include <QString>
#include <QStringList>
#include <QFileInfo>
#include <QUuid>
#include "../basetypes.h"
#include "../ffs.h"
#include "../ffsengine.h"
class UEFIReplace : public QObject
{
Q_OBJECT
public:
explicit UEFIReplace(QObject *parent = 0);
~UEFIReplace();
UINT8 replace(const QString inPath, const QByteArray & guid, const UINT8 sectionType, const QString contentPath);
private:
UINT8 replaceInFile(const QModelIndex & index, const QByteArray & guid, const UINT8 sectionType, const QByteArray & contents);
FfsEngine* ffsEngine;
TreeModel* model;
};
#endif

View file

@ -0,0 +1,42 @@
QT += core
QT -= gui
TARGET = UEFIReplace
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
DEFINES += _CONSOLE
SOURCES += uefireplace_main.cpp \
uefireplace.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 += uefireplace.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

View file

@ -0,0 +1,78 @@
/* uefireplace_main.cpp
Copyright (c) 2017, mxxxc. 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 "uefireplace.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
a.setOrganizationName("CodeRush");
a.setOrganizationDomain("coderush.me");
a.setApplicationName("UEFIReplace");
UEFIReplace r;
UINT8 result = ERR_SUCCESS;
QStringList args = a.arguments();
if (args.length() < 5) {
std::cout << "UEFIReplace 0.3.9 - UEFI image file replacement utility" << std::endl << std::endl <<
"Usage: UEFIReplace image_file guid section_type contents_file" << std::endl;
return ERR_SUCCESS;
}
QUuid uuid = QUuid(args.at(2));
QByteArray guid = QByteArray::fromRawData((const char*)&uuid.data1, sizeof(EFI_GUID));
bool converted;
UINT8 sectionType = (UINT8)args.at(3).toUShort(&converted, 16);
if (!converted)
result = ERR_INVALID_PARAMETER;
else
result = r.replace(args.at(1), guid, sectionType, args.at(4));
switch (result) {
case ERR_SUCCESS:
std::cout << "File replaced" << std::endl;
break;
case ERR_INVALID_PARAMETER:
std::cout << "Function called with invalid parameter" << std::endl;
break;
case ERR_INVALID_FILE:
std::cout << "Invalid/corrupted file specified" << std::endl;
break;
case ERR_INVALID_SECTION:
std::cout << "Invalid/corrupted section specified" << std::endl;
break;
case ERR_NOTHING_TO_PATCH:
std::cout << "No replacements can be applied to input file" << std::endl;
break;
case ERR_NOT_IMPLEMENTED:
std::cout << "Can't replace body of this section type" << 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;
}

View file

@ -1,146 +0,0 @@
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" )

View file

@ -1,33 +0,0 @@
<?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>

View file

@ -1,91 +0,0 @@
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()

View file

@ -1,20 +0,0 @@
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.

View file

@ -1,56 +0,0 @@
#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;
};

View file

@ -1,24 +0,0 @@
#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};
};

View file

@ -1,29 +0,0 @@
#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;
};

View file

@ -1,20 +0,0 @@
#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};
};

View file

@ -1,22 +0,0 @@
#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;
};

View file

@ -1,12 +0,0 @@
#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;
};

View file

@ -1,19 +0,0 @@
#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;
};

View file

@ -1,11 +0,0 @@
#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;
};

View file

@ -1,11 +0,0 @@
#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;
};

View file

@ -1,14 +0,0 @@
#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;
};

View file

@ -1,73 +0,0 @@
#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;
};

View file

@ -1,30 +0,0 @@
#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;
};

View file

@ -1,102 +0,0 @@
#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);
}

View file

@ -1,92 +0,0 @@
#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;
};

View file

@ -1,56 +0,0 @@
#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; }
};

View file

@ -1,66 +0,0 @@
#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

View file

@ -1,184 +0,0 @@
#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;
};

View file

@ -1,418 +0,0 @@
#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());
}

View file

@ -1,118 +0,0 @@
#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;
}

View file

@ -1,36 +0,0 @@
#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);
}

View file

@ -1,51 +0,0 @@
#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());
}

View file

@ -1,39 +0,0 @@
#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));
}

View file

@ -1,26 +0,0 @@
#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));
}

View file

@ -1,6 +0,0 @@
#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) {}

View file

@ -1,18 +0,0 @@
#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); }

View file

@ -1,20 +0,0 @@
#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);
}

View file

@ -1,21 +0,0 @@
#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);
}

View file

@ -1,182 +0,0 @@
#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);
}

View file

@ -1,65 +0,0 @@
#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);
}

View file

@ -1,142 +0,0 @@
#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);
}

View file

@ -1,158 +0,0 @@
#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);
}

View file

@ -1,384 +0,0 @@
#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

File diff suppressed because it is too large Load diff

View file

@ -1,276 +0,0 @@
/* 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, &regexpmatch);
#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, &regexpmatch);
#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, &regexpmatch);
#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, &regexpmatch);
#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;
}

View file

@ -1,50 +0,0 @@
/* 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

View file

@ -1,36 +0,0 @@
/* 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

View file

@ -1,133 +0,0 @@
<?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>

View file

@ -1,36 +0,0 @@
/* 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

View file

@ -1,133 +0,0 @@
<?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>

View file

@ -1,86 +0,0 @@
/* 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);
}

View file

@ -1,41 +0,0 @@
/* 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);
}

Some files were not shown because too many files have changed in this diff Show more