build: Replace old interval tree in favour of custom libwolv one
This commit is contained in:
parent
1d2b8ac1f3
commit
50c3cf8272
@ -442,14 +442,12 @@ macro(addBundledLibraries)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL)
|
||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/intervaltree EXCLUDE_FROM_ALL)
|
||||
set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL)
|
||||
set_property(TARGET libwolv-types PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-utils PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-io PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-hash PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-containers PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
|
||||
set(XDGPP_INCLUDE_DIRS "${EXTERN_LIBS_FOLDER}/xdgpp")
|
||||
|
6
dist/rpm/imhex.spec
vendored
6
dist/rpm/imhex.spec
vendored
@ -4,7 +4,7 @@ Release: 0%{?dist}
|
||||
Summary: A hex editor for reverse engineers and programmers
|
||||
|
||||
License: GPL-2.0-only AND Zlib AND MIT AND Apache-2.0
|
||||
# imhex is gplv2. capstone is custom. nativefiledialog is Zlib. intervaltree is MIT
|
||||
# imhex is gplv2. capstone is custom. nativefiledialog is Zlib.
|
||||
# see license dir for full breakdown
|
||||
URL: https://imhex.werwolv.net/
|
||||
# We need the archive with deps bundled
|
||||
@ -36,9 +36,6 @@ Provides: bundled(imgui)
|
||||
Provides: bundled(libromfs)
|
||||
Provides: bundled(microtar)
|
||||
Provides: bundled(libpl)
|
||||
# ImHex modified upstream intervaltree so we have to package it
|
||||
# https://github.com/ekg/intervaltree
|
||||
Provides: bundled(intervaltree) = 0.1
|
||||
Provides: bundled(xdgpp)
|
||||
|
||||
# ftbfs on these arches. armv7hl might compile when capstone 5.x
|
||||
@ -115,7 +112,6 @@ cp -a lib/external/nativefiledialog/LICENSE %{buildroot}%{
|
||||
cp -a lib/external/capstone/LICENSE.TXT %{buildroot}%{_datadir}/licenses/%{name}/capstone-LICENSE
|
||||
cp -a lib/external/capstone/suite/regress/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/capstone-regress-LICENSE
|
||||
cp -a lib/external/microtar/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/microtar-LICENSE
|
||||
cp -a lib/external/pattern_language/external/intervaltree/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/pattern-language-intervaltree-LICENSE
|
||||
cp -a lib/external/xdgpp/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/xdgpp-LICENSE
|
||||
|
||||
|
||||
|
9
lib/external/intervaltree/CMakeLists.txt
vendored
9
lib/external/intervaltree/CMakeLists.txt
vendored
@ -1,9 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(intervaltree)
|
||||
|
||||
set(CMAKE_CXX_STANDARD20)
|
||||
|
||||
add_library(intervaltree INTERFACE)
|
||||
|
||||
target_include_directories(intervaltree INTERFACE include)
|
||||
target_compile_options(intervaltree INTERFACE "-DUSE_INTERVAL_TREE_NAMESPACE")
|
23
lib/external/intervaltree/LICENSE
vendored
23
lib/external/intervaltree/LICENSE
vendored
@ -1,23 +0,0 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2019 Dana-Farber Cancer Institute
|
||||
|
||||
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.
|
133
lib/external/intervaltree/README.md
vendored
133
lib/external/intervaltree/README.md
vendored
@ -1,133 +0,0 @@
|
||||
## Introduction
|
||||
|
||||
cgranges is a small C library for genomic interval overlap queries: given a
|
||||
genomic region *r* and a set of regions *R*, finding all regions in *R* that
|
||||
overlaps *r*. Although this library is based on [interval tree][itree], a well
|
||||
known data structure, the core algorithm of cgranges is distinct from all
|
||||
existing implementations to the best of our knowledge. Specifically, the
|
||||
interval tree in cgranges is implicitly encoded as a plain sorted array
|
||||
(similar to [binary heap][bheap] but packed differently). Tree
|
||||
traversal is achieved by jumping between array indices. This treatment makes
|
||||
cgranges very efficient and compact in memory. The core algorithm can be
|
||||
implemented in ~50 lines of C++ code, much shorter than others as well. Please
|
||||
see the code comments in [cpp/IITree.h](cpp/IITree.h) for details.
|
||||
|
||||
## Usage
|
||||
|
||||
### Test with BED coverage
|
||||
|
||||
For testing purposes, this repo implements the [bedtools coverage][bedcov] tool
|
||||
with cgranges. The source code is located in the [test/](test) directory. You
|
||||
can compile and run the test with:
|
||||
```sh
|
||||
cd test && make
|
||||
./bedcov-cr test1.bed test2.bed
|
||||
```
|
||||
The first BED file is loaded into RAM and indexed. The depth and the breadth of
|
||||
coverage of each region in the second file is computed by query against the
|
||||
index of the first file.
|
||||
|
||||
The [test/](test) directory also contains a few other implementations based on
|
||||
[IntervalTree.h][ekg-itree] in C++, [quicksect][quicksect] in Cython and
|
||||
[ncls][ncls] in Cython. The table below shows timing and peak memory on two
|
||||
test BEDs available in the release page. The first BED contains GenCode
|
||||
annotations with ~1.2 million lines, mixing all types of features. The second
|
||||
contains ~10 million direct-RNA mappings. Time1a/Mem1a indexes the GenCode BED
|
||||
into memory. Time1b adds whole chromosome intervals to the GenCode BED when
|
||||
indexing. Time2/Mem2 indexes the RNA-mapping BED into memory. Numbers are
|
||||
averaged over 5 runs.
|
||||
|
||||
|Algo. |Lang. |Cov|Program |Time1a|Time1b|Mem1a |Time2 |Mem2 |
|
||||
|:-------|:-----|:-:|:---------------|-----:|-----:|-------:|-----:|-------:|
|
||||
|IAITree |C |Y |cgranges |9.0s |13.9s |19.1MB |4.6s |138.4MB |
|
||||
|IAITree |C++ |Y |cpp/iitree.h |11.1s |24.5s |22.4MB |5.8s |160.4MB |
|
||||
|CITree |C++ |Y |IntervalTree.h |17.4s |17.4s |27.2MB |10.5s |179.5MB |
|
||||
|IAITree |C |N |cgranges |7.6s |13.0s |19.1MB |4.1s |138.4MB |
|
||||
|AIList |C |N |3rd-party/AIList|7.9s |8.1s |14.4MB |6.5s |104.8MB |
|
||||
|NCList |C |N |3rd-party/NCList|13.0s |13.4s |21.4MB |10.6s |183.0MB |
|
||||
|AITree |C |N |3rd-party/AITree|16.8s |18.4s |73.4MB |27.3s |546.4MB |
|
||||
|IAITree |Cython|N |cgranges |56.6s |63.9s |23.4MB |43.9s |143.1MB |
|
||||
|binning |C++ |Y |bedtools |201.9s|280.4s|478.5MB |149.1s|3438.1MB|
|
||||
|
||||
Here, IAITree = implicit augmented interval tree, used by cgranges;
|
||||
CITree = centered interval tree, used by [Erik Garrison's
|
||||
IntervalTree][itree]; AIList = augmented interval list, by [Feng et
|
||||
al][ailist]; NCList = nested containment list, taken from [ncls][ncls] by Feng
|
||||
et al; AITree = augmented interval tree, from [kerneltree][kerneltree].
|
||||
"Cov" indicates whether the program calculates breadth of coverage.
|
||||
Comments:
|
||||
|
||||
* AIList keeps start and end only. IAITree and CITree addtionally store a
|
||||
4-byte "ID" field per interval to reference the source of interval. This is
|
||||
partly why AIList uses the least memory.
|
||||
|
||||
* IAITree is more sensitive to the worse case: the presence of an interval
|
||||
spanning the whole chromosome.
|
||||
|
||||
* IAITree uses an efficient radix sort. CITree uses std::sort from STL, which
|
||||
is ok. AIList and NCList use qsort from libc, which is slow. Faster sorting
|
||||
leads to faster indexing.
|
||||
|
||||
* IAITree in C++ uses identical core algorithm to the C version, but limited by
|
||||
its APIs, it wastes time on memory locality and management. CITree has a
|
||||
similar issue.
|
||||
|
||||
* Computing coverage is better done when the returned list of intervals are
|
||||
start sorted. IAITree returns sorted list. CITree doesn't. Not sure about
|
||||
others. Computing coverage takes a couple of seconds. Sorting will be slower.
|
||||
|
||||
* Printing intervals also takes a noticeable fraction of time. Custom printf
|
||||
equivalent would be faster.
|
||||
|
||||
* IAITree+Cython is a wrapper around the C version of cgranges. Cython adds
|
||||
significant overhead.
|
||||
|
||||
* Bedtools is designed for a variety of applications in addition to computing
|
||||
coverage. It may keep other information in its internal data structure. This
|
||||
micro-benchmark may be unfair to bedtools.
|
||||
|
||||
* In general, the performance is affected a lot by subtle implementation
|
||||
details. CITree, IAITree, NCList and AIList are all broadly comparable in
|
||||
performance. AITree is not recommended when indexed intervals are immutable.
|
||||
|
||||
### Use cgranges as a C library
|
||||
|
||||
```c
|
||||
cgranges_t *cr = cr_init(); // initialize a cgranges_t object
|
||||
cr_add(cr, "chr1", 20, 30, 0); // add a genomic interval
|
||||
cr_add(cr, "chr2", 10, 30, 1);
|
||||
cr_add(cr, "chr1", 10, 25, 2);
|
||||
cr_index(cr); // index
|
||||
|
||||
int64_t i, n, *b = 0, max_b = 0;
|
||||
n = cr_overlap(cr, "chr1", 15, 22, &b, &max_b); // overlap query; output array b[] can be reused
|
||||
for (i = 0; i < n; ++i) // traverse overlapping intervals
|
||||
printf("%d\t%d\t%d\n", cr_start(cr, b[i]), cr_end(cr, b[i]), cr_label(cr, b[i]));
|
||||
free(b); // b[] is allocated by malloc() inside cr_overlap(), so needs to be freed with free()
|
||||
|
||||
cr_destroy(cr);
|
||||
```
|
||||
|
||||
### Use IITree as a C++ library
|
||||
|
||||
```cpp
|
||||
IITree<int, int> tree;
|
||||
tree.add(12, 34, 0); // add an interval
|
||||
tree.add(0, 23, 1);
|
||||
tree.add(34, 56, 2);
|
||||
tree.index(); // index
|
||||
std::vector<size_t> a;
|
||||
tree.overlap(22, 25, a); // retrieve overlaps
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
printf("%d\t%d\t%d\n", tree.start(a[i]), tree.end(a[i]), tree.data(a[i]));
|
||||
```
|
||||
|
||||
[bedcov]: https://bedtools.readthedocs.io/en/latest/content/tools/coverage.html
|
||||
[ekg-itree]: https://github.com/ekg/intervaltree
|
||||
[quicksect]: https://github.com/brentp/quicksect
|
||||
[ncls]: https://github.com/hunt-genes/ncls
|
||||
[citree]: https://en.wikipedia.org/wiki/Interval_tree#Centered_interval_tree
|
||||
[itree]: https://en.wikipedia.org/wiki/Interval_tree
|
||||
[bheap]: https://en.wikipedia.org/wiki/Binary_heap
|
||||
[ailist]: https://www.biorxiv.org/content/10.1101/593657v1
|
||||
[kerneltree]: https://github.com/biocore-ntnu/kerneltree
|
88
lib/external/intervaltree/include/IITree.h
vendored
88
lib/external/intervaltree/include/IITree.h
vendored
@ -1,88 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
template<typename S, typename T> // "S" is a scalar type; "T" is the type of data associated with each interval
|
||||
class IITree {
|
||||
struct StackCell {
|
||||
size_t x; // node
|
||||
int w; // w: 0 if left child hasn't been processed
|
||||
StackCell() {};
|
||||
StackCell(size_t x_, int w_) : x(x_), w(w_) {};
|
||||
};
|
||||
struct Interval {
|
||||
S st, en, max;
|
||||
T data;
|
||||
Interval() = default;
|
||||
Interval(const S &s, const S &e, const T &d) : st(s), en(e), max(e), data(d) { }
|
||||
};
|
||||
struct IntervalLess {
|
||||
bool operator()(const Interval &intervalA, const Interval &intervalB) const { return intervalA.st < intervalB.st; }
|
||||
};
|
||||
std::vector<Interval> a;
|
||||
size_t layout_recur(Interval *b, size_t i = 0, size_t k = 0) { // see https://algorithmica.org/en/eytzinger
|
||||
if (k < a.size()) {
|
||||
i = layout_recur(b, i, (k<<1) + 1);
|
||||
b[k] = a[i++];
|
||||
i = layout_recur(b, i, (k<<1) + 2);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
void index_BFS(Interval *interval, size_t n) { // set Interval::max
|
||||
int t = 0;
|
||||
StackCell stack[64];
|
||||
stack[t++] = StackCell(0, 0);
|
||||
while (t) {
|
||||
StackCell z = stack[--t];
|
||||
size_t k = z.x, l = k<<1|1, r = l + 1;
|
||||
if (z.w == 2) { // Interval::max for both children are computed
|
||||
interval[k].max = interval[k].en;
|
||||
if (l < n && interval[k].max < interval[l].max) interval[k].max = interval[l].max;
|
||||
if (r < n && interval[k].max < interval[r].max) interval[k].max = interval[r].max;
|
||||
} else { // go down into the two children
|
||||
stack[t++] = StackCell(k, z.w + 1);
|
||||
if (l + z.w < n)
|
||||
stack[t++] = StackCell(l + z.w, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
void add(const S &s, const S &e, const T &d) { a.push_back(Interval(s, e, d)); }
|
||||
void index() {
|
||||
std::sort(a.begin(), a.end(), IntervalLess());
|
||||
std::vector<Interval> b(a.size());
|
||||
layout_recur(b.data());
|
||||
a.clear();
|
||||
std::copy(b.begin(), b.end(), std::back_inserter(a));
|
||||
index_BFS(a.data(), a.size());
|
||||
}
|
||||
bool overlap(const S &st, const S &en, std::vector<size_t> &out) const {
|
||||
int t = 0;
|
||||
std::array<StackCell, 64> stack;
|
||||
out.clear();
|
||||
if (a.empty()) return false;
|
||||
stack[t++] = StackCell(0, 0); // push the root; this is a top down traversal
|
||||
while (t) { // the following guarantees that numbers in out[] are always sorted
|
||||
StackCell z = stack[--t];
|
||||
size_t l = (z.x<<1) + 1, r = l + 1;
|
||||
if (l >= a.size()) { // a leaf node
|
||||
if (st < a[z.x].en && a[z.x].st <= en) out.push_back(z.x);
|
||||
} else if (z.w == 0) { // if left child not processed
|
||||
stack[t++] = StackCell(z.x, 1); // re-add node z.x, but mark the left child having been processed
|
||||
if (l < a.size() && a[l].max > st)
|
||||
stack[t++] = StackCell(l, 0);
|
||||
} else if (a[z.x].st <= en) { // need to push the right child
|
||||
if (st < a[z.x].en) out.push_back(z.x); // test if z.x overlaps the query; if yes, append to out[]
|
||||
if (r < a.size()) stack[t++] = StackCell(r, 0);
|
||||
}
|
||||
}
|
||||
return out.size() > 0? true : false;
|
||||
}
|
||||
size_t size(void) const { return a.size(); }
|
||||
const S &start(size_t i) const { return a[i].st; }
|
||||
const S &end(size_t i) const { return a[i].en; }
|
||||
const T &data(size_t i) const { return a[i].data; }
|
||||
};
|
2
lib/external/libwolv
vendored
2
lib/external/libwolv
vendored
@ -1 +1 @@
|
||||
Subproject commit 2ccf828f79a30c8524ad79bbaea44f33e2d43227
|
||||
Subproject commit 30c8014d22cebcbb791305b27ff054de4d60e211
|
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
@ -1 +1 @@
|
||||
Subproject commit 4af40da17ac91b43d4f5832dfc47dec7301d2145
|
||||
Subproject commit 1ace51d331e6e2dca64492a73c20a2a9331b6c9b
|
@ -69,4 +69,4 @@ elseif (APPLE)
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PRIVATE ${FMT_LIBRARIES})
|
||||
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} libpl intervaltree ${MINIAUDIO_LIBRARIES} libwolv-utils libwolv-io libwolv-hash libwolv-net)
|
||||
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} libpl ${MINIAUDIO_LIBRARIES} libwolv-utils libwolv-io libwolv-hash libwolv-net libwolv-containers)
|
@ -29,11 +29,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override;
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override;
|
||||
/**
|
||||
* @brief closes the file streams used to read the file.
|
||||
* Need to be called on file write, see https://github.com/WerWolv/ImHex/issues/988
|
||||
*/
|
||||
void invalidateFiles();
|
||||
|
||||
[[nodiscard]] size_t getActualSize() const override;
|
||||
|
||||
void save() override;
|
||||
@ -60,20 +56,16 @@ namespace hex::plugin::builtin {
|
||||
|
||||
[[nodiscard]] std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
private:
|
||||
wolv::io::File& getFile();
|
||||
|
||||
protected:
|
||||
std::fs::path m_path;
|
||||
wolv::io::File m_file;
|
||||
size_t m_fileSize = 0;
|
||||
|
||||
wolv::io::File m_sizeFile;
|
||||
std::map<std::thread::id, wolv::io::File> m_files;
|
||||
std::atomic<u32> m_mapCounter = 0;
|
||||
|
||||
std::optional<struct stat> m_fileStats;
|
||||
|
||||
bool m_readable = false, m_writable = false;
|
||||
|
||||
std::mutex m_fileAccessMutex, m_writeMutex;
|
||||
};
|
||||
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <IITree.h>
|
||||
#include <wolv/container/interval_tree.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@ -44,7 +44,7 @@ namespace hex::plugin::builtin {
|
||||
protected:
|
||||
bool m_dataValid = false;
|
||||
size_t m_dataSize = 0x00;
|
||||
IITree<u64, std::vector<u8>> m_data;
|
||||
wolv::container::IntervalTree<std::vector<u8>, u64, 0> m_data;
|
||||
|
||||
std::fs::path m_sourceFilePath;
|
||||
};
|
||||
|
@ -12,8 +12,6 @@
|
||||
|
||||
#include "ui/hex_editor.hpp"
|
||||
|
||||
#include <IITree.h>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
class ViewDiff : public View {
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include <IITree.h>
|
||||
#include <wolv/container/interval_tree.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@ -94,7 +94,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
} m_searchSettings, m_decodeSettings;
|
||||
|
||||
using OccurrenceTree = IITree<u64, Occurrence>;
|
||||
using OccurrenceTree = wolv::container::IntervalTree<Occurrence, u64, 0>;
|
||||
|
||||
PerProvider<std::vector<Occurrence>> m_foundOccurrences, m_sortedOccurrences;
|
||||
PerProvider<OccurrenceTree> m_occurrenceTree;
|
||||
|
@ -86,9 +86,6 @@ namespace hex::plugin::builtin {
|
||||
this->close();
|
||||
}
|
||||
);
|
||||
|
||||
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
||||
this->close();
|
||||
}
|
||||
|
||||
[[nodiscard]] ImGuiWindowFlags getFlags() const override {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
|
||||
@ -60,24 +59,28 @@ namespace hex::plugin::builtin {
|
||||
if (offset > (this->getActualSize() - size) || buffer == nullptr || size == 0)
|
||||
return;
|
||||
|
||||
auto &file = this->getFile();
|
||||
file.seek(offset);
|
||||
file.readBuffer(reinterpret_cast<u8*>(buffer), size);
|
||||
/*auto currSize = std::fs::file_size(this->m_path);
|
||||
if (this->m_fileSize != currSize) [[unlikely]] {
|
||||
this->m_fileSize = currSize;
|
||||
this->m_file.unmap();
|
||||
this->m_file.map();
|
||||
}*/
|
||||
|
||||
std::memcpy(buffer, this->m_file.getMapping() + offset, size);
|
||||
}
|
||||
|
||||
void FileProvider::writeRaw(u64 offset, const void *buffer, size_t size) {
|
||||
if ((offset + size) > this->getActualSize() || buffer == nullptr || size == 0)
|
||||
return;
|
||||
|
||||
std::scoped_lock lock(this->m_writeMutex);
|
||||
wolv::io::File writeFile(this->m_path, wolv::io::File::Mode::Write);
|
||||
if (!writeFile.isValid())
|
||||
return;
|
||||
auto currSize = std::fs::file_size(this->m_path);
|
||||
if (this->m_fileSize != currSize) [[unlikely]] {
|
||||
this->m_fileSize = currSize;
|
||||
this->m_file.unmap();
|
||||
this->m_file.map();
|
||||
}
|
||||
|
||||
writeFile.seek(offset);
|
||||
writeFile.writeBuffer(reinterpret_cast<const u8*>(buffer), size);
|
||||
|
||||
this->invalidateFiles();
|
||||
std::memcpy(this->m_file.getMapping() + offset, buffer, size);
|
||||
}
|
||||
|
||||
void FileProvider::save() {
|
||||
@ -125,13 +128,6 @@ namespace hex::plugin::builtin {
|
||||
Provider::insert(offset, size);
|
||||
}
|
||||
|
||||
void FileProvider::invalidateFiles() {
|
||||
for(auto & [threadId, file] : this->m_files){
|
||||
file.close();
|
||||
}
|
||||
this->m_files.clear();
|
||||
}
|
||||
|
||||
void FileProvider::remove(u64 offset, size_t size) {
|
||||
auto oldSize = this->getActualSize();
|
||||
this->resize(oldSize + size);
|
||||
@ -156,7 +152,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
size_t FileProvider::getActualSize() const {
|
||||
return this->m_sizeFile.getSize();
|
||||
return this->m_fileSize;
|
||||
}
|
||||
|
||||
std::string FileProvider::getName() const {
|
||||
@ -220,9 +216,10 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
this->m_fileStats = file.getFileInfo();
|
||||
this->m_sizeFile = file.clone();
|
||||
this->m_file = std::move(file);
|
||||
|
||||
this->m_files.emplace(std::this_thread::get_id(), std::move(file));
|
||||
this->m_file.map();
|
||||
this->m_fileSize = this->m_file.getSize();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -231,18 +228,6 @@ namespace hex::plugin::builtin {
|
||||
|
||||
}
|
||||
|
||||
wolv::io::File& FileProvider::getFile() {
|
||||
|
||||
auto threadId = std::this_thread::get_id();
|
||||
if (!this->m_files.contains(threadId)) {
|
||||
std::scoped_lock lock(this->m_fileAccessMutex);
|
||||
if (!this->m_files.contains(threadId))
|
||||
this->m_files.emplace(threadId, this->m_sizeFile.clone());
|
||||
}
|
||||
|
||||
return this->m_files[threadId];
|
||||
}
|
||||
|
||||
void FileProvider::loadSettings(const nlohmann::json &settings) {
|
||||
Provider::loadSettings(settings);
|
||||
|
||||
|
@ -161,37 +161,25 @@ namespace hex::plugin::builtin {
|
||||
void IntelHexProvider::setBaseAddress(u64 address) {
|
||||
auto oldBase = this->getBaseAddress();
|
||||
|
||||
std::vector<size_t> indices;
|
||||
this->m_data.overlap(oldBase, oldBase + this->getActualSize(), indices);
|
||||
auto regions = this->m_data.overlapping({ oldBase, oldBase + this->getActualSize() });
|
||||
|
||||
IITree<u64, std::vector<u8>> intervals;
|
||||
for (auto &index : indices) {
|
||||
intervals.add(
|
||||
(this->m_data.start(index) - oldBase) + address,
|
||||
(this->m_data.end(index) - oldBase) + address,
|
||||
this->m_data.data(index)
|
||||
);
|
||||
decltype(this->m_data) newIntervals;
|
||||
for (auto &[interval, data] : regions) {
|
||||
newIntervals.insert({ interval.start - oldBase + address, interval.end - oldBase + address }, *data);
|
||||
}
|
||||
|
||||
this->m_data = std::move(intervals);
|
||||
this->m_data.index();
|
||||
this->m_data = newIntervals;
|
||||
|
||||
Provider::setBaseAddress(address);
|
||||
}
|
||||
|
||||
void IntelHexProvider::readRaw(u64 offset, void *buffer, size_t size) {
|
||||
std::vector<size_t> indices;
|
||||
this->m_data.overlap(offset, (offset + size) - 1, indices);
|
||||
auto intervals = this->m_data.overlapping({ offset, (offset + size) - 1 });
|
||||
|
||||
std::memset(buffer, 0x00, size);
|
||||
auto bytes = reinterpret_cast<u8*>(buffer);
|
||||
for (const auto &index : indices) {
|
||||
auto start = this->m_data.start(index);
|
||||
auto end = this->m_data.end(index);
|
||||
auto data = this->m_data.data(index);
|
||||
|
||||
for (u32 i = std::max(start, offset); i <= end && (i - offset) < size; i++) {
|
||||
bytes[i - offset] = data[i - start];
|
||||
for (const auto &[interval, data] : intervals) {
|
||||
for (u32 i = std::max(interval.start, offset); i <= interval.end && (i - offset) < size; i++) {
|
||||
bytes[i - offset] = (*data)[i - interval.start];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -216,12 +204,11 @@ namespace hex::plugin::builtin {
|
||||
u64 maxAddress = 0x00;
|
||||
for (auto &[address, bytes] : data) {
|
||||
auto endAddress = (address + bytes.size()) - 1;
|
||||
this->m_data.add(address, endAddress, std::move(bytes));
|
||||
this->m_data.emplace({ address, endAddress }, std::move(bytes));
|
||||
|
||||
if (endAddress > maxAddress)
|
||||
maxAddress = endAddress;
|
||||
}
|
||||
this->m_data.index();
|
||||
|
||||
this->m_dataSize = maxAddress + 1;
|
||||
this->m_dataValid = true;
|
||||
@ -265,22 +252,18 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
std::pair<Region, bool> IntelHexProvider::getRegionValidity(u64 address) const {
|
||||
std::vector<size_t> indices;
|
||||
this->m_data.overlap(address, address, indices);
|
||||
if (indices.empty()) {
|
||||
auto intervals = this->m_data.overlapping({ address, address });
|
||||
if (intervals.empty()) {
|
||||
return Provider::getRegionValidity(address);
|
||||
}
|
||||
|
||||
auto closestIndex = indices.front();
|
||||
for (const auto &index : indices) {
|
||||
if (this->m_data.start(index) < this->m_data.start(closestIndex))
|
||||
closestIndex = index;
|
||||
decltype(this->m_data)::Interval closestInterval = { 0, 0 };
|
||||
for (const auto &[interval, data] : intervals) {
|
||||
if (interval.start < closestInterval.end)
|
||||
closestInterval = interval;
|
||||
}
|
||||
return { Region { closestInterval.start, (closestInterval.end - closestInterval.start) + 1}, true };
|
||||
|
||||
auto start = this->m_data.start(closestIndex);
|
||||
auto end = this->m_data.end(closestIndex);
|
||||
|
||||
return { Region { start, (end - start) + 1 }, true };
|
||||
}
|
||||
|
||||
void IntelHexProvider::loadSettings(const nlohmann::json &settings) {
|
||||
|
@ -182,12 +182,11 @@ namespace hex::plugin::builtin {
|
||||
u64 maxAddress = 0x00;
|
||||
for (auto &[address, bytes] : data) {
|
||||
auto endAddress = (address + bytes.size()) - 1;
|
||||
this->m_data.add(address, endAddress, std::move(bytes));
|
||||
this->m_data.emplace({ address, endAddress }, std::move(bytes));
|
||||
|
||||
if (endAddress > maxAddress)
|
||||
maxAddress = endAddress;
|
||||
}
|
||||
this->m_data.index();
|
||||
|
||||
this->m_dataSize = maxAddress + 1;
|
||||
this->m_dataValid = true;
|
||||
|
@ -22,8 +22,7 @@ namespace hex::plugin::builtin {
|
||||
if (this->m_searchTask.isRunning())
|
||||
return { };
|
||||
|
||||
std::vector<size_t> occurrences;
|
||||
if (this->m_occurrenceTree->overlap(address, address, occurrences))
|
||||
if (!this->m_occurrenceTree->overlapping({ address, address }).empty())
|
||||
return HighlightColor();
|
||||
else
|
||||
return std::nullopt;
|
||||
@ -35,8 +34,8 @@ namespace hex::plugin::builtin {
|
||||
if (this->m_searchTask.isRunning())
|
||||
return;
|
||||
|
||||
std::vector<size_t> occurrences;
|
||||
if (!this->m_occurrenceTree->overlap(address, address, occurrences))
|
||||
auto occurrences = this->m_occurrenceTree->overlapping({ address, address });
|
||||
if (occurrences.empty())
|
||||
return;
|
||||
|
||||
ImGui::BeginTooltip();
|
||||
@ -48,10 +47,8 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
{
|
||||
auto start = this->m_occurrenceTree->start(occurrence);
|
||||
auto end = this->m_occurrenceTree->end(occurrence) - 1;
|
||||
const auto &bytes = this->m_occurrenceTree->data(occurrence);
|
||||
const auto value = this->decodeValue(ImHexApi::Provider::get(), bytes, 256);
|
||||
auto region = occurrence.value.region;
|
||||
const auto value = this->decodeValue(ImHexApi::Provider::get(), occurrence.value, 256);
|
||||
|
||||
ImGui::ColorButton("##color", ImColor(HighlightColor()));
|
||||
ImGui::SameLine(0, 10);
|
||||
@ -65,7 +62,7 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.common.region"_lang);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", start, end);
|
||||
ImGui::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", region.getStartAddress(), region.getEndAddress());
|
||||
|
||||
auto demangledValue = llvm::demangle(value);
|
||||
|
||||
@ -513,8 +510,7 @@ namespace hex::plugin::builtin {
|
||||
this->m_sortedOccurrences.get(provider) = this->m_foundOccurrences.get(provider);
|
||||
|
||||
for (const auto &occurrence : this->m_foundOccurrences.get(provider))
|
||||
this->m_occurrenceTree->add(occurrence.region.getStartAddress(), occurrence.region.getEndAddress() + 1, occurrence);
|
||||
this->m_occurrenceTree->index();
|
||||
this->m_occurrenceTree->insert({ occurrence.region.getStartAddress(), occurrence.region.getEndAddress() }, occurrence);
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user