mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-31 13:26:02 -05:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
066161f397 | ||
|
|
d3e3de3fa2 | ||
|
|
194bc3e5be | ||
|
|
a9e3db0464 | ||
|
|
334ba3ede2 | ||
|
|
7978964995 | ||
|
|
d5ca4c4f28 | ||
|
|
08c2e1cd4e | ||
|
|
2f6e91cd9e | ||
|
|
888976873a | ||
|
|
5db608c3fc | ||
|
|
e46807c600 | ||
|
|
7799bbb57a | ||
|
|
7da8a5b1d8 | ||
|
|
ae9f4fa876 | ||
|
|
e3dd5900e2 | ||
|
|
aab865fe25 | ||
|
|
62656f4c51 | ||
|
|
b323d711cf | ||
|
|
9b4cf917d9 | ||
|
|
ba97573f93 | ||
|
|
9dc62e1469 | ||
|
|
55c0cb66e3 | ||
|
|
a8526585cb | ||
|
|
3850349eae | ||
|
|
f5bd0b7971 | ||
|
|
42d9753bdb | ||
|
|
17d5a5309a | ||
|
|
71be77c54b | ||
|
|
93c1fbd65e | ||
|
|
c8114347dc | ||
|
|
3c2c2b003f | ||
|
|
2edd6cd6c4 | ||
|
|
6713f65040 | ||
|
|
82ee4ad4ca | ||
|
|
d9134f7fe1 | ||
|
|
ee26839292 | ||
|
|
cd33376c07 | ||
|
|
e57481b87c | ||
|
|
5601aab043 | ||
|
|
1b7a1852bc |
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# Updating the version here will update it throughout ImHex as well
|
||||
set(IMHEX_VERSION "1.10.0")
|
||||
set(IMHEX_VERSION "1.10.1")
|
||||
project(imhex VERSION ${IMHEX_VERSION})
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
@@ -17,39 +17,16 @@ set(PLUGINS
|
||||
# example
|
||||
)
|
||||
|
||||
# List extra magic databases to compile here
|
||||
set(MAGICDBS
|
||||
magic_dbs/nintendo_magic
|
||||
)
|
||||
|
||||
findLibraries()
|
||||
|
||||
detectOS()
|
||||
detectArch()
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
add_subdirectory(external/llvm)
|
||||
else()
|
||||
find_package(LLVM REQUIRED Demangle)
|
||||
endif()
|
||||
if (NOT USE_SYSTEM_YARA)
|
||||
add_subdirectory(external/yara)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
|
||||
endif()
|
||||
|
||||
# Add bundled dependencies
|
||||
add_subdirectory(plugins/libimhex)
|
||||
|
||||
# Add include directories
|
||||
include_directories(include ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${Python_INCLUDE_DIRS})
|
||||
if (USE_SYSTEM_LLVM)
|
||||
include_directories(include ${LLVM_INCLUDE_DIRS})
|
||||
endif()
|
||||
if (USE_SYSTEM_YARA)
|
||||
include_directories(include ${YARA_INCLUDE_DIRS})
|
||||
endif()
|
||||
include_directories(include)
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
@@ -100,12 +77,11 @@ add_executable(imhex ${application_type}
|
||||
)
|
||||
|
||||
set_target_properties(imhex PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
target_link_directories(imhex PRIVATE ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(imhex ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} wsock32 ws2_32 libyara Dwmapi.lib dl)
|
||||
target_link_libraries(imhex dl libimhex wsock32 ws2_32 Dwmapi.lib)
|
||||
else ()
|
||||
target_link_libraries(imhex ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} dl pthread libyara)
|
||||
target_link_libraries(imhex dl libimhex pthread)
|
||||
endif ()
|
||||
|
||||
createPackage()
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace ImGui {
|
||||
Texture LoadImageFromMemory(ImU8 *buffer, int size);
|
||||
void UnloadImage(Texture &texture);
|
||||
|
||||
void OpenPopupInWindow(const char *window_name, const char *popup_name);
|
||||
|
||||
struct ImHexCustomData {
|
||||
ImVec4 Colors[ImGuiCustomCol_COUNT];
|
||||
|
||||
@@ -357,6 +357,13 @@ namespace ImGui {
|
||||
texture = { nullptr, 0, 0 };
|
||||
}
|
||||
|
||||
void OpenPopupInWindow(const char *window_name, const char *popup_name) {
|
||||
if (ImGui::Begin(window_name)) {
|
||||
ImGui::OpenPopup(popup_name);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
bool TitleBarButton(const char* label, ImVec2 size_arg) {
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
|
||||
10
external/microtar/CMakeLists.txt
vendored
Normal file
10
external/microtar/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(microtar)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
|
||||
add_library(microtar STATIC
|
||||
source/microtar.c
|
||||
)
|
||||
|
||||
target_include_directories(microtar PUBLIC include)
|
||||
19
external/microtar/LICENSE
vendored
Normal file
19
external/microtar/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2017 rxi
|
||||
|
||||
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.
|
||||
99
external/microtar/README.md
vendored
Normal file
99
external/microtar/README.md
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
# microtar
|
||||
A lightweight tar library written in ANSI C
|
||||
|
||||
|
||||
## Basic Usage
|
||||
The library consists of `microtar.c` and `microtar.h`. These two files can be
|
||||
dropped into an existing project and compiled along with it.
|
||||
|
||||
|
||||
#### Reading
|
||||
```c
|
||||
mtar_t tar;
|
||||
mtar_header_t h;
|
||||
char *p;
|
||||
|
||||
/* Open archive for reading */
|
||||
mtar_open(&tar, "test.tar", "r");
|
||||
|
||||
/* Print all file names and sizes */
|
||||
while ( (mtar_read_header(&tar, &h)) != MTAR_ENULLRECORD ) {
|
||||
printf("%s (%d bytes)\n", h.name, h.size);
|
||||
mtar_next(&tar);
|
||||
}
|
||||
|
||||
/* Load and print contents of file "test.txt" */
|
||||
mtar_find(&tar, "test.txt", &h);
|
||||
p = calloc(1, h.size + 1);
|
||||
mtar_read_data(&tar, p, h.size);
|
||||
printf("%s", p);
|
||||
free(p);
|
||||
|
||||
/* Close archive */
|
||||
mtar_close(&tar);
|
||||
```
|
||||
|
||||
#### Writing
|
||||
```c
|
||||
mtar_t tar;
|
||||
const char *str1 = "Hello world";
|
||||
const char *str2 = "Goodbye world";
|
||||
|
||||
/* Open archive for writing */
|
||||
mtar_open(&tar, "test.tar", "w");
|
||||
|
||||
/* Write strings to files `test1.txt` and `test2.txt` */
|
||||
mtar_write_file_header(&tar, "test1.txt", strlen(str1));
|
||||
mtar_write_data(&tar, str1, strlen(str1));
|
||||
mtar_write_file_header(&tar, "test2.txt", strlen(str2));
|
||||
mtar_write_data(&tar, str2, strlen(str2));
|
||||
|
||||
/* Finalize -- this needs to be the last thing done before closing */
|
||||
mtar_finalize(&tar);
|
||||
|
||||
/* Close archive */
|
||||
mtar_close(&tar);
|
||||
```
|
||||
|
||||
|
||||
## Error handling
|
||||
All functions which return an `int` will return `MTAR_ESUCCESS` if the operation
|
||||
is successful. If an error occurs an error value less-than-zero will be
|
||||
returned; this value can be passed to the function `mtar_strerror()` to get its
|
||||
corresponding error string.
|
||||
|
||||
|
||||
## Wrapping a stream
|
||||
If you want to read or write from something other than a file, the `mtar_t`
|
||||
struct can be manually initialized with your own callback functions and a
|
||||
`stream` pointer.
|
||||
|
||||
All callback functions are passed a pointer to the `mtar_t` struct as their
|
||||
first argument. They should return `MTAR_ESUCCESS` if the operation succeeds
|
||||
without an error, or an integer below zero if an error occurs.
|
||||
|
||||
After the `stream` field has been set, all required callbacks have been set and
|
||||
all unused fields have been zeroset the `mtar_t` struct can be safely used with
|
||||
the microtar functions. `mtar_open` *should not* be called if the `mtar_t`
|
||||
struct was initialized manually.
|
||||
|
||||
#### Reading
|
||||
The following callbacks should be set for reading an archive from a stream:
|
||||
|
||||
Name | Arguments | Description
|
||||
--------|------------------------------------------|---------------------------
|
||||
`read` | `mtar_t *tar, void *data, unsigned size` | Read data from the stream
|
||||
`seek` | `mtar_t *tar, unsigned pos` | Set the position indicator
|
||||
`close` | `mtar_t *tar` | Close the stream
|
||||
|
||||
#### Writing
|
||||
The following callbacks should be set for writing an archive to a stream:
|
||||
|
||||
Name | Arguments | Description
|
||||
--------|------------------------------------------------|---------------------
|
||||
`write` | `mtar_t *tar, const void *data, unsigned size` | Write data to the stream
|
||||
|
||||
|
||||
## License
|
||||
This library is free software; you can redistribute it and/or modify it under
|
||||
the terms of the MIT license. See [LICENSE](LICENSE) for details.
|
||||
93
external/microtar/include/microtar.h
vendored
Normal file
93
external/microtar/include/microtar.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2017 rxi
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the MIT license. See `microtar.c` for details.
|
||||
*/
|
||||
|
||||
#ifndef MICROTAR_H
|
||||
#define MICROTAR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MTAR_VERSION "0.1.0"
|
||||
|
||||
enum {
|
||||
MTAR_ESUCCESS = 0,
|
||||
MTAR_EFAILURE = -1,
|
||||
MTAR_EOPENFAIL = -2,
|
||||
MTAR_EREADFAIL = -3,
|
||||
MTAR_EWRITEFAIL = -4,
|
||||
MTAR_ESEEKFAIL = -5,
|
||||
MTAR_EBADCHKSUM = -6,
|
||||
MTAR_ENULLRECORD = -7,
|
||||
MTAR_ENOTFOUND = -8
|
||||
};
|
||||
|
||||
enum {
|
||||
MTAR_TREG = '0',
|
||||
MTAR_TLNK = '1',
|
||||
MTAR_TSYM = '2',
|
||||
MTAR_TCHR = '3',
|
||||
MTAR_TBLK = '4',
|
||||
MTAR_TDIR = '5',
|
||||
MTAR_TFIFO = '6'
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned mode;
|
||||
unsigned owner;
|
||||
unsigned size;
|
||||
unsigned mtime;
|
||||
unsigned type;
|
||||
char name[100];
|
||||
char linkname[100];
|
||||
} mtar_header_t;
|
||||
|
||||
|
||||
typedef struct mtar_t mtar_t;
|
||||
|
||||
struct mtar_t {
|
||||
int (*read)(mtar_t *tar, void *data, unsigned size);
|
||||
|
||||
int (*write)(mtar_t *tar, const void *data, unsigned size);
|
||||
|
||||
int (*seek)(mtar_t *tar, unsigned pos);
|
||||
|
||||
int (*close)(mtar_t *tar);
|
||||
|
||||
void *stream;
|
||||
unsigned pos;
|
||||
unsigned remaining_data;
|
||||
unsigned last_header;
|
||||
};
|
||||
|
||||
|
||||
const char *mtar_strerror(int err);
|
||||
|
||||
int mtar_open(mtar_t *tar, const char *filename, const char *mode);
|
||||
int mtar_close(mtar_t *tar);
|
||||
|
||||
int mtar_seek(mtar_t *tar, unsigned pos);
|
||||
int mtar_rewind(mtar_t *tar);
|
||||
int mtar_next(mtar_t *tar);
|
||||
int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h);
|
||||
int mtar_read_header(mtar_t *tar, mtar_header_t *h);
|
||||
int mtar_read_data(mtar_t *tar, void *ptr, unsigned size);
|
||||
|
||||
int mtar_write_header(mtar_t *tar, const mtar_header_t *h);
|
||||
int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size);
|
||||
int mtar_write_dir_header(mtar_t *tar, const char *name);
|
||||
int mtar_write_data(mtar_t *tar, const void *data, unsigned size);
|
||||
int mtar_finalize(mtar_t *tar);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
376
external/microtar/source/microtar.c
vendored
Normal file
376
external/microtar/source/microtar.c
vendored
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (c) 2017 rxi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <microtar.h>
|
||||
|
||||
typedef struct {
|
||||
char name[100];
|
||||
char mode[8];
|
||||
char owner[8];
|
||||
char group[8];
|
||||
char size[12];
|
||||
char mtime[12];
|
||||
char checksum[8];
|
||||
char type;
|
||||
char linkname[100];
|
||||
char _padding[255];
|
||||
} mtar_raw_header_t;
|
||||
|
||||
|
||||
static unsigned round_up(unsigned n, unsigned incr) {
|
||||
return n + (incr - n % incr) % incr;
|
||||
}
|
||||
|
||||
|
||||
static unsigned checksum(const mtar_raw_header_t* rh) {
|
||||
unsigned i;
|
||||
unsigned char *p = (unsigned char*) rh;
|
||||
unsigned res = 256;
|
||||
for (i = 0; i < offsetof(mtar_raw_header_t, checksum); i++) {
|
||||
res += p[i];
|
||||
}
|
||||
for (i = offsetof(mtar_raw_header_t, type); i < sizeof(*rh); i++) {
|
||||
res += p[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int tread(mtar_t *tar, void *data, unsigned size) {
|
||||
int err = tar->read(tar, data, size);
|
||||
tar->pos += size;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int twrite(mtar_t *tar, const void *data, unsigned size) {
|
||||
int err = tar->write(tar, data, size);
|
||||
tar->pos += size;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int write_null_bytes(mtar_t *tar, int n) {
|
||||
int i, err;
|
||||
char nul = '\0';
|
||||
for (i = 0; i < n; i++) {
|
||||
err = twrite(tar, &nul, 1);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) {
|
||||
unsigned chksum1, chksum2;
|
||||
|
||||
/* If the checksum starts with a null byte we assume the record is NULL */
|
||||
if (*rh->checksum == '\0') {
|
||||
return MTAR_ENULLRECORD;
|
||||
}
|
||||
|
||||
/* Build and compare checksum */
|
||||
chksum1 = checksum(rh);
|
||||
sscanf(rh->checksum, "%o", &chksum2);
|
||||
if (chksum1 != chksum2) {
|
||||
return MTAR_EBADCHKSUM;
|
||||
}
|
||||
|
||||
/* Load raw header into header */
|
||||
sscanf(rh->mode, "%o", &h->mode);
|
||||
sscanf(rh->owner, "%o", &h->owner);
|
||||
sscanf(rh->size, "%o", &h->size);
|
||||
sscanf(rh->mtime, "%o", &h->mtime);
|
||||
h->type = rh->type;
|
||||
strcpy(h->name, rh->name);
|
||||
strcpy(h->linkname, rh->linkname);
|
||||
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h) {
|
||||
unsigned chksum;
|
||||
|
||||
/* Load header into raw header */
|
||||
memset(rh, 0, sizeof(*rh));
|
||||
sprintf(rh->mode, "%o", h->mode);
|
||||
sprintf(rh->owner, "%o", h->owner);
|
||||
sprintf(rh->size, "%o", h->size);
|
||||
sprintf(rh->mtime, "%o", h->mtime);
|
||||
rh->type = h->type ? h->type : MTAR_TREG;
|
||||
strcpy(rh->name, h->name);
|
||||
strcpy(rh->linkname, h->linkname);
|
||||
|
||||
/* Calculate and write checksum */
|
||||
chksum = checksum(rh);
|
||||
sprintf(rh->checksum, "%06o", chksum);
|
||||
rh->checksum[7] = ' ';
|
||||
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
const char* mtar_strerror(int err) {
|
||||
switch (err) {
|
||||
case MTAR_ESUCCESS : return "success";
|
||||
case MTAR_EFAILURE : return "failure";
|
||||
case MTAR_EOPENFAIL : return "could not open";
|
||||
case MTAR_EREADFAIL : return "could not read";
|
||||
case MTAR_EWRITEFAIL : return "could not write";
|
||||
case MTAR_ESEEKFAIL : return "could not seek";
|
||||
case MTAR_EBADCHKSUM : return "bad checksum";
|
||||
case MTAR_ENULLRECORD : return "null record";
|
||||
case MTAR_ENOTFOUND : return "file not found";
|
||||
}
|
||||
return "unknown error";
|
||||
}
|
||||
|
||||
|
||||
static int file_write(mtar_t *tar, const void *data, unsigned size) {
|
||||
unsigned res = fwrite(data, 1, size, tar->stream);
|
||||
return (res == size) ? MTAR_ESUCCESS : MTAR_EWRITEFAIL;
|
||||
}
|
||||
|
||||
static int file_read(mtar_t *tar, void *data, unsigned size) {
|
||||
unsigned res = fread(data, 1, size, tar->stream);
|
||||
return (res == size) ? MTAR_ESUCCESS : MTAR_EREADFAIL;
|
||||
}
|
||||
|
||||
static int file_seek(mtar_t *tar, unsigned offset) {
|
||||
int res = fseek(tar->stream, offset, SEEK_SET);
|
||||
return (res == 0) ? MTAR_ESUCCESS : MTAR_ESEEKFAIL;
|
||||
}
|
||||
|
||||
static int file_close(mtar_t *tar) {
|
||||
fclose(tar->stream);
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mtar_open(mtar_t *tar, const char *filename, const char *mode) {
|
||||
int err;
|
||||
mtar_header_t h;
|
||||
|
||||
/* Init tar struct and functions */
|
||||
memset(tar, 0, sizeof(*tar));
|
||||
tar->write = file_write;
|
||||
tar->read = file_read;
|
||||
tar->seek = file_seek;
|
||||
tar->close = file_close;
|
||||
|
||||
/* Assure mode is always binary */
|
||||
if ( strchr(mode, 'r') ) mode = "rb";
|
||||
if ( strchr(mode, 'w') ) mode = "wb";
|
||||
if ( strchr(mode, 'a') ) mode = "ab";
|
||||
/* Open file */
|
||||
tar->stream = fopen(filename, mode);
|
||||
if (!tar->stream) {
|
||||
return MTAR_EOPENFAIL;
|
||||
}
|
||||
/* Read first header to check it is valid if mode is `r` */
|
||||
if (*mode == 'r') {
|
||||
err = mtar_read_header(tar, &h);
|
||||
if (err != MTAR_ESUCCESS) {
|
||||
mtar_close(tar);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return ok */
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mtar_close(mtar_t *tar) {
|
||||
return tar->close(tar);
|
||||
}
|
||||
|
||||
|
||||
int mtar_seek(mtar_t *tar, unsigned pos) {
|
||||
int err = tar->seek(tar, pos);
|
||||
tar->pos = pos;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int mtar_rewind(mtar_t *tar) {
|
||||
tar->remaining_data = 0;
|
||||
tar->last_header = 0;
|
||||
return mtar_seek(tar, 0);
|
||||
}
|
||||
|
||||
|
||||
int mtar_next(mtar_t *tar) {
|
||||
int err, n;
|
||||
mtar_header_t h;
|
||||
/* Load header */
|
||||
err = mtar_read_header(tar, &h);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
/* Seek to next record */
|
||||
n = round_up(h.size, 512) + sizeof(mtar_raw_header_t);
|
||||
return mtar_seek(tar, tar->pos + n);
|
||||
}
|
||||
|
||||
|
||||
int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h) {
|
||||
int err;
|
||||
mtar_header_t header;
|
||||
/* Start at beginning */
|
||||
err = mtar_rewind(tar);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
/* Iterate all files until we hit an error or find the file */
|
||||
while ( (err = mtar_read_header(tar, &header)) == MTAR_ESUCCESS ) {
|
||||
if ( !strcmp(header.name, name) ) {
|
||||
if (h) {
|
||||
*h = header;
|
||||
}
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
mtar_next(tar);
|
||||
}
|
||||
/* Return error */
|
||||
if (err == MTAR_ENULLRECORD) {
|
||||
err = MTAR_ENOTFOUND;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int mtar_read_header(mtar_t *tar, mtar_header_t *h) {
|
||||
int err;
|
||||
mtar_raw_header_t rh;
|
||||
/* Save header position */
|
||||
tar->last_header = tar->pos;
|
||||
/* Read raw header */
|
||||
err = tread(tar, &rh, sizeof(rh));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
/* Seek back to start of header */
|
||||
err = mtar_seek(tar, tar->last_header);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
/* Load raw header into header struct and return */
|
||||
return raw_to_header(h, &rh);
|
||||
}
|
||||
|
||||
|
||||
int mtar_read_data(mtar_t *tar, void *ptr, unsigned size) {
|
||||
int err;
|
||||
/* If we have no remaining data then this is the first read, we get the size,
|
||||
* set the remaining data and seek to the beginning of the data */
|
||||
if (tar->remaining_data == 0) {
|
||||
mtar_header_t h;
|
||||
/* Read header */
|
||||
err = mtar_read_header(tar, &h);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
/* Seek past header and init remaining data */
|
||||
err = mtar_seek(tar, tar->pos + sizeof(mtar_raw_header_t));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
tar->remaining_data = h.size;
|
||||
}
|
||||
/* Read data */
|
||||
err = tread(tar, ptr, size);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
tar->remaining_data -= size;
|
||||
/* If there is no remaining data we've finished reading and seek back to the
|
||||
* header */
|
||||
if (tar->remaining_data == 0) {
|
||||
return mtar_seek(tar, tar->last_header);
|
||||
}
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mtar_write_header(mtar_t *tar, const mtar_header_t *h) {
|
||||
mtar_raw_header_t rh;
|
||||
/* Build raw header and write */
|
||||
header_to_raw(&rh, h);
|
||||
tar->remaining_data = h->size;
|
||||
return twrite(tar, &rh, sizeof(rh));
|
||||
}
|
||||
|
||||
|
||||
int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size) {
|
||||
mtar_header_t h;
|
||||
/* Build header */
|
||||
memset(&h, 0, sizeof(h));
|
||||
strcpy(h.name, name);
|
||||
h.size = size;
|
||||
h.type = MTAR_TREG;
|
||||
h.mode = 0664;
|
||||
/* Write header */
|
||||
return mtar_write_header(tar, &h);
|
||||
}
|
||||
|
||||
|
||||
int mtar_write_dir_header(mtar_t *tar, const char *name) {
|
||||
mtar_header_t h;
|
||||
/* Build header */
|
||||
memset(&h, 0, sizeof(h));
|
||||
strcpy(h.name, name);
|
||||
h.type = MTAR_TDIR;
|
||||
h.mode = 0775;
|
||||
/* Write header */
|
||||
return mtar_write_header(tar, &h);
|
||||
}
|
||||
|
||||
|
||||
int mtar_write_data(mtar_t *tar, const void *data, unsigned size) {
|
||||
int err;
|
||||
/* Write data */
|
||||
err = twrite(tar, data, size);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
tar->remaining_data -= size;
|
||||
/* Write padding if we've written all the data for this file */
|
||||
if (tar->remaining_data == 0) {
|
||||
return write_null_bytes(tar, round_up(tar->pos, 512) - tar->pos);
|
||||
}
|
||||
return MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mtar_finalize(mtar_t *tar) {
|
||||
/* Write two NULL records */
|
||||
return write_null_bytes(tar, sizeof(mtar_raw_header_t) * 2);
|
||||
}
|
||||
@@ -26,12 +26,14 @@ namespace hex {
|
||||
|
||||
private:
|
||||
pl::PatternLanguage *m_patternLanguageRuntime;
|
||||
std::vector<std::string> m_possiblePatternFiles;
|
||||
int m_selectedPatternFile = 0;
|
||||
std::vector<std::filesystem::path> m_possiblePatternFiles;
|
||||
u32 m_selectedPatternFile = 0;
|
||||
bool m_runAutomatically = false;
|
||||
bool m_evaluatorRunning = false;
|
||||
bool m_hasUnevaluatedChanges = false;
|
||||
|
||||
bool m_acceptPatternWindowOpen = false;
|
||||
|
||||
TextEditor m_textEditor;
|
||||
std::vector<std::pair<pl::LogConsole::Level, std::string>> m_console;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <array>
|
||||
#include <future>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -19,6 +20,8 @@ namespace hex {
|
||||
std::string link;
|
||||
std::string hash;
|
||||
|
||||
bool isFolder;
|
||||
|
||||
bool downloading;
|
||||
bool installed;
|
||||
bool hasUpdate;
|
||||
@@ -39,8 +42,9 @@ namespace hex {
|
||||
Net m_net;
|
||||
std::future<Response<std::string>> m_apiRequest;
|
||||
std::future<Response<void>> m_download;
|
||||
std::filesystem::path m_downloadPath;
|
||||
|
||||
std::vector<StoreEntry> m_patterns, m_includes, m_magics, m_constants;
|
||||
std::vector<StoreEntry> m_patterns, m_includes, m_magics, m_constants, m_yara;
|
||||
|
||||
void drawStore();
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace hex {
|
||||
bool wholeDataMatch;
|
||||
};
|
||||
|
||||
std::vector<std::string> m_rules;
|
||||
std::vector<std::pair<std::string, std::string>> m_rules;
|
||||
std::vector<YaraMatch> m_matches;
|
||||
u32 m_selectedRule = 0;
|
||||
bool m_matching = false;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/views/view.hpp>
|
||||
@@ -64,6 +65,8 @@ namespace hex {
|
||||
ImGui::Texture m_logoTexture;
|
||||
|
||||
std::filesystem::path m_safetyBackupPath;
|
||||
|
||||
std::list<std::string> m_popupsToOpen;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
namespace std::math {
|
||||
|
||||
fn min_u(u128 a, u128 b) {
|
||||
return (a < b) ? a : b;
|
||||
};
|
||||
|
||||
fn min_i(s128 a, s128 b) {
|
||||
return (a < b) ? a : b;
|
||||
};
|
||||
|
||||
fn min_f(double a, double b) {
|
||||
return (a < b) ? a : b;
|
||||
};
|
||||
|
||||
|
||||
fn max_u(u128 a, u128 b) {
|
||||
return (a > b) ? a : b;
|
||||
};
|
||||
|
||||
fn max_i(s128 a, s128 b) {
|
||||
return (a > b) ? a : b;
|
||||
};
|
||||
|
||||
fn max_f(double a, double b) {
|
||||
return (a > b) ? a : b;
|
||||
};
|
||||
|
||||
|
||||
fn abs_i(s128 value) {
|
||||
return value < 0 ? -value : value;
|
||||
};
|
||||
|
||||
fn abs_d(double value) {
|
||||
return value < 0 ? -value : value;
|
||||
};
|
||||
|
||||
|
||||
fn ceil(double value) {
|
||||
s128 cast;
|
||||
cast = value;
|
||||
|
||||
return cast + 1;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
std::print("{}", std::math::ceil(123.6));
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <hex/helpers/shared_data.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/net.hpp>
|
||||
|
||||
#include <hex/pattern_language/token.hpp>
|
||||
#include <hex/pattern_language/log_console.hpp>
|
||||
@@ -177,17 +178,17 @@ namespace hex::plugin::builtin {
|
||||
|
||||
}
|
||||
|
||||
ContentRegistry::PatternLanguageFunctions::Namespace nsStdStr = { "std", "str" };
|
||||
ContentRegistry::PatternLanguageFunctions::Namespace nsStdString = { "std", "string" };
|
||||
{
|
||||
/* length(string) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "length", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "length", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto string = Token::literalToString(params[0], false);
|
||||
|
||||
return u128(string.length());
|
||||
});
|
||||
|
||||
/* at(string, index) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "at", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "at", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto string = Token::literalToString(params[0], false);
|
||||
auto index = Token::literalToSigned(params[1]);
|
||||
|
||||
@@ -201,17 +202,43 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
/* substr(string, pos, count) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "substr", 3, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "substr", 3, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto string = Token::literalToString(params[0], false);
|
||||
auto pos = Token::literalToUnsigned(params[1]);
|
||||
auto size = Token::literalToUnsigned(params[2]);
|
||||
|
||||
if (pos > size)
|
||||
if (pos > string.length())
|
||||
LogConsole::abortEvaluation("character index out of range");
|
||||
|
||||
return string.substr(pos, size);
|
||||
});
|
||||
|
||||
/* parse_int(string, base) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "parse_int", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto string = Token::literalToString(params[0], false);
|
||||
auto base = Token::literalToUnsigned(params[1]);
|
||||
|
||||
return s128(std::strtoll(string.c_str(), nullptr, base));
|
||||
});
|
||||
|
||||
/* parse_float(string) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "parse_float", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
auto string = Token::literalToString(params[0], false);
|
||||
|
||||
return double(std::strtod(string.c_str(), nullptr));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
ContentRegistry::PatternLanguageFunctions::Namespace nsStdHttp = { "std", "http" };
|
||||
{
|
||||
/* get(url) */
|
||||
ContentRegistry::PatternLanguageFunctions::add(nsStdHttp, "get", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
const auto url = Token::literalToString(params[0], false);
|
||||
|
||||
hex::Net net;
|
||||
return net.getString(url).get().body;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,17 @@ namespace hex::plugin::builtin {
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
/* Interface */
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", 0, [](auto name, nlohmann::json &setting) {
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
#include <hex/helpers/shared_data.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/literals.hpp>
|
||||
|
||||
#include <regex>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
|
||||
#include <llvm/Demangle/Demangle.h>
|
||||
#include "math_evaluator.hpp"
|
||||
@@ -24,6 +28,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
using namespace std::literals::chrono_literals;
|
||||
using namespace hex::literals;
|
||||
|
||||
int updateStringSizeCallback(ImGuiInputTextCallbackData *data) {
|
||||
auto &mathInput = *static_cast<std::string*>(data->UserData);
|
||||
@@ -666,6 +671,371 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void drawFileToolShredder() {
|
||||
static bool shredding = false;
|
||||
static auto selectedFile = []{ std::string s; s.reserve(0x1000); return s; }();
|
||||
static bool fastMode = false;
|
||||
|
||||
ImGui::TextUnformatted("hex.builtin.tools.file_tools.shredder.warning"_lang);
|
||||
ImGui::NewLine();
|
||||
|
||||
if (ImGui::BeginChild("settings", { 0, ImGui::GetTextLineHeightWithSpacing() * 4 }, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||
ImGui::BeginDisabled(shredding);
|
||||
{
|
||||
ImGui::TextUnformatted("hex.builtin.tools.file_tools.shredder.input"_lang);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##path", selectedFile.data(), selectedFile.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &selectedFile);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("...")) {
|
||||
hex::openFileBrowser("hex.builtin.tools.file_tools.shredder.picker"_lang, DialogMode::Open, {}, [](const std::string &path) {
|
||||
selectedFile = path;
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::Checkbox("hex.builtin.tools.file_tools.shredder.fast"_lang, &fastMode);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
if (shredding)
|
||||
ImGui::TextSpinner("hex.builtin.tools.file_tools.shredder.shredding"_lang);
|
||||
else {
|
||||
ImGui::BeginDisabled(selectedFile.empty());
|
||||
{
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.shredder.shred"_lang)) {
|
||||
shredding = true;
|
||||
|
||||
std::thread([]{
|
||||
ON_SCOPE_EXIT { shredding = false; selectedFile.clear(); };
|
||||
File file(selectedFile, File::Mode::Write);
|
||||
|
||||
if (!file.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.tools.file_tools.shredder.error.open"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::array<u8, 3>> overwritePattern;
|
||||
if (fastMode) {
|
||||
/* Should be sufficient for modern disks */
|
||||
overwritePattern.push_back({ 0x00, 0x00, 0x00 });
|
||||
overwritePattern.push_back({ 0xFF, 0xFF, 0xFF });
|
||||
}
|
||||
else {
|
||||
/* Gutmann's method. Secure for magnetic storage */
|
||||
std::random_device rd;
|
||||
std::uniform_int_distribution<u8> dist(0x00, 0xFF);
|
||||
|
||||
/* Fill fixed patterns */
|
||||
overwritePattern = {
|
||||
{}, {}, {}, {},
|
||||
{ 0x55, 0x55, 0x55 }, { 0xAA, 0xAA, 0xAA }, { 0x92, 0x49, 0x24 }, { 0x49, 0x24, 0x92 },
|
||||
{ 0x24, 0x92, 0x49 }, { 0x00, 0x00, 0x00 }, { 0x11, 0x11, 0x11 }, { 0x22, 0x22, 0x22 },
|
||||
{ 0x33, 0x33, 0x44 }, { 0x55, 0x55, 0x55 }, { 0x66, 0x66, 0x66 }, { 0x77, 0x77, 0x77 },
|
||||
{ 0x88, 0x88, 0x88 }, { 0x99, 0x99, 0x99 }, { 0xAA, 0xAA, 0xAA }, { 0xBB, 0xBB, 0xBB },
|
||||
{ 0xCC, 0xCC, 0xCC }, { 0xDD, 0xDD, 0xDD }, { 0xEE, 0xEE, 0xEE }, { 0xFF, 0xFF, 0xFF },
|
||||
{ 0x92, 0x49, 0x24 }, { 0x49, 0x24, 0x92 }, { 0x24, 0x92, 0x49 }, { 0x6D, 0xB6, 0xDB },
|
||||
{ 0xB6, 0xDB, 0x6D }, { 0xBD, 0x6D, 0xB6 },
|
||||
{}, {}, {}, {}
|
||||
};
|
||||
|
||||
/* Fill random patterns */
|
||||
for (u8 i = 0; i < 4; i++)
|
||||
overwritePattern[i] = { dist(rd), dist(rd), dist(rd) };
|
||||
for (u8 i = 0; i < 4; i++)
|
||||
overwritePattern[overwritePattern.size() - 1 - i] = { dist(rd), dist(rd), dist(rd) };
|
||||
}
|
||||
|
||||
size_t fileSize = file.getSize();
|
||||
for (const auto &pattern : overwritePattern) {
|
||||
for (u64 offset = 0; offset < fileSize; offset += 3) {
|
||||
file.write(pattern.data(), std::min(pattern.size(), fileSize - offset));
|
||||
}
|
||||
file.flush();
|
||||
}
|
||||
|
||||
file.remove();
|
||||
|
||||
View::showMessagePopup("hex.builtin.tools.file_tools.shredder.success"_lang);
|
||||
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
void drawFileToolSplitter() {
|
||||
std::array sizeText = {
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.zip100"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.zip200"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.cdrom650"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.cdrom700"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.fat32"_lang,
|
||||
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.custom"_lang
|
||||
};
|
||||
std::array<u64, sizeText.size()> sizes = {
|
||||
1200_KiB,
|
||||
1400_KiB,
|
||||
100_MiB,
|
||||
200_MiB,
|
||||
650_MiB,
|
||||
700_MiB,
|
||||
4_GiB,
|
||||
1
|
||||
};
|
||||
|
||||
static bool splitting = false;
|
||||
static auto selectedFile = []{ std::string s; s.reserve(0x1000); return s; }();
|
||||
static auto baseOutputPath = []{ std::string s; s.reserve(0x1000); return s; }();
|
||||
static u64 splitSize = sizes[0];
|
||||
static int selectedItem = 0;
|
||||
|
||||
if (ImGui::BeginChild("split_settings", { 0, ImGui::GetTextLineHeightWithSpacing() * 7 }, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||
ImGui::BeginDisabled(splitting);
|
||||
{
|
||||
ImGui::TextUnformatted("hex.builtin.tools.file_tools.splitter.input"_lang);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##path", selectedFile.data(), selectedFile.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &selectedFile);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("...##input")) {
|
||||
hex::openFileBrowser("hex.builtin.tools.file_tools.splitter.picker.input"_lang, DialogMode::Open, {}, [](const std::string &path) {
|
||||
selectedFile = path;
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted("hex.builtin.tools.file_tools.splitter.output"_lang);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##base_path", baseOutputPath.data(), baseOutputPath.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &baseOutputPath);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("...##output")) {
|
||||
hex::openFileBrowser("hex.builtin.tools.file_tools.splitter.picker.output"_lang, DialogMode::Save, {}, [](const std::string &path) {
|
||||
baseOutputPath = path;
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Combo("###part_size", &selectedItem, sizeText.data(), sizeText.size())) {
|
||||
splitSize = sizes[selectedItem];
|
||||
}
|
||||
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::BeginDisabled(splitting || selectedItem != sizes.size() - 1);
|
||||
{
|
||||
ImGui::InputScalar("###custom_size", ImGuiDataType_U64, &splitSize);
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted("Bytes");
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::BeginDisabled(selectedFile.empty() || baseOutputPath.empty() || splitSize == 0);
|
||||
{
|
||||
if (splitting)
|
||||
ImGui::TextSpinner("hex.builtin.tools.file_tools.splitter.splitting"_lang);
|
||||
else {
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.splitter.split"_lang)) {
|
||||
splitting = true;
|
||||
|
||||
std::thread([]{
|
||||
ON_SCOPE_EXIT { splitting = false; selectedFile.clear(); baseOutputPath.clear(); };
|
||||
File file(selectedFile, File::Mode::Read);
|
||||
|
||||
if (!file.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.tools.file_tools.splitter.error.open"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.getSize() < splitSize) {
|
||||
View::showErrorPopup("hex.builtin.tools.file_tools.splitter.error.size"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 index = 1;
|
||||
for (u64 offset = 0; offset < file.getSize(); offset += splitSize) {
|
||||
File partFile(baseOutputPath + hex::format(".{:05}", index), File::Mode::Create);
|
||||
|
||||
if (!partFile.isValid()) {
|
||||
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.splitter.error.create"_lang, index));
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr auto BufferSize = 0xFF'FFFF;
|
||||
for (u64 partOffset = 0; partOffset < splitSize; partOffset += BufferSize) {
|
||||
partFile.write(file.readBytes(std::min<u64>(BufferSize, splitSize - partOffset)));
|
||||
partFile.flush();
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
View::showMessagePopup("hex.builtin.tools.file_tools.splitter.success"_lang);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
void drawFileToolCombiner() {
|
||||
static bool combining = false;
|
||||
static std::vector<std::string> files;
|
||||
static auto outputPath = []{ std::string s; s.reserve(0x1000); return s; }();
|
||||
static s32 selectedIndex;
|
||||
|
||||
if (ImGui::BeginTable("files_table", 2, ImGuiTableFlags_SizingStretchProp)) {
|
||||
ImGui::TableSetupColumn("file list", ImGuiTableColumnFlags_NoHeaderLabel, 10);
|
||||
ImGui::TableSetupColumn("buttons", ImGuiTableColumnFlags_NoHeaderLabel, 1);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (ImGui::BeginListBox("##files", { -FLT_MIN, 10 * ImGui::GetTextLineHeightWithSpacing() })) {
|
||||
|
||||
s32 index = 0;
|
||||
for (auto &file : files) {
|
||||
if (ImGui::Selectable(std::filesystem::path(file).filename().string().c_str(), index == selectedIndex))
|
||||
selectedIndex = index;
|
||||
index++;
|
||||
}
|
||||
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::BeginDisabled(selectedIndex <= 0) ;
|
||||
{
|
||||
if (ImGui::ArrowButton("move_up", ImGuiDir_Up)) {
|
||||
std::iter_swap(files.begin() + selectedIndex, files.begin() + selectedIndex - 1);
|
||||
selectedIndex--;
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::BeginDisabled(files.empty() || selectedIndex >= files.size() - 1) ;
|
||||
{
|
||||
if (ImGui::ArrowButton("move_down", ImGuiDir_Down)) {
|
||||
std::iter_swap(files.begin() + selectedIndex, files.begin() + selectedIndex + 1);
|
||||
selectedIndex++;
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::BeginDisabled(combining);
|
||||
{
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.add"_lang)) {
|
||||
hex::openFileBrowser("hex.builtin.tools.file_tools.combiner.add.picker"_lang, DialogMode::Open, {}, [](const std::string &path) {
|
||||
files.push_back(path);
|
||||
});
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.delete"_lang)) {
|
||||
files.erase(files.begin() + selectedIndex);
|
||||
selectedIndex--;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.clear"_lang)) {
|
||||
files.clear();
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::BeginDisabled(combining);
|
||||
{
|
||||
ImGui::TextUnformatted("hex.builtin.tools.file_tools.combiner.output"_lang);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##output_path", outputPath.data(), outputPath.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &outputPath);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("...")) {
|
||||
hex::openFileBrowser("hex.builtin.tools.file_tools.combiner.output.picker"_lang, DialogMode::Save, {}, [](const std::string &path) {
|
||||
outputPath = path;
|
||||
});
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::BeginDisabled(files.empty() || outputPath.empty());
|
||||
{
|
||||
if (combining)
|
||||
ImGui::TextSpinner("hex.builtin.tools.file_tools.combiner.combining"_lang);
|
||||
else {
|
||||
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.combine"_lang)) {
|
||||
combining = true;
|
||||
|
||||
std::thread([]{
|
||||
ON_SCOPE_EXIT { combining = false; };
|
||||
|
||||
File output(outputPath, File::Mode::Create);
|
||||
|
||||
if (!output.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.tools.file_tools.combiner.error.open_output"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &file : files) {
|
||||
File input(file, File::Mode::Read);
|
||||
|
||||
if (!input.isValid()) {
|
||||
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, std::filesystem::path(file).filename().string()));
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr auto BufferSize = 0xFF'FFFF;
|
||||
auto inputSize = input.getSize();
|
||||
for (u64 inputOffset = 0; inputOffset < inputSize; inputOffset += BufferSize) {
|
||||
output.write(input.readBytes(std::min<u64>(BufferSize, inputSize - inputOffset)));
|
||||
output.flush();
|
||||
}
|
||||
}
|
||||
|
||||
files.clear();
|
||||
selectedIndex = 0;
|
||||
outputPath.clear();
|
||||
|
||||
View::showMessagePopup("hex.builtin.tools.file_tools.combiner.success"_lang);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
}
|
||||
|
||||
void drawFileTools() {
|
||||
|
||||
if (ImGui::BeginTabBar("file_tools_tabs")) {
|
||||
|
||||
if (ImGui::BeginTabItem("hex.builtin.tools.file_tools.shredder"_lang)) {
|
||||
drawFileToolShredder();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("hex.builtin.tools.file_tools.splitter"_lang)) {
|
||||
drawFileToolSplitter();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("hex.builtin.tools.file_tools.combiner"_lang)) {
|
||||
drawFileToolCombiner();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
}
|
||||
|
||||
void registerToolEntries() {
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.demangler", drawDemangler);
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.ascii_table", drawASCIITable);
|
||||
@@ -676,6 +1046,7 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.permissions", drawPermissionsCalculator);
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.file_uploader", drawFileUploader);
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.wiki_explain", drawWikiExplainer);
|
||||
ContentRegistry::Tools::add("hex.builtin.tools.file_tools", drawFileTools);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -63,6 +63,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.decimal", "Dezimal" },
|
||||
{ "hex.common.hexadecimal", "Hexadezimal" },
|
||||
{ "hex.common.octal", "Oktal" },
|
||||
{ "hex.common.info", "Information" },
|
||||
{ "hex.common.error", "Fehler" },
|
||||
{ "hex.common.fatal", "Fataler Fehler" },
|
||||
{ "hex.common.address", "Adresse" },
|
||||
@@ -79,10 +80,15 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.dont_show_again", "Nicht mehr anzeigen" },
|
||||
{ "hex.common.link", "Link" },
|
||||
{ "hex.common.file", "Datei" },
|
||||
{ "hex.common.open", "Öffnen" },
|
||||
{ "hex.common.browse", "Druchsuchen..." },
|
||||
|
||||
{ "hex.message.yara_rule_added", "Yara Regel hinzugefügt!" },
|
||||
{ "hex.message.magic_db_added", "Magic Datenbank hinzugefügt!" },
|
||||
|
||||
{ "hex.view.bookmarks.name", "Lesezeichen" },
|
||||
{ "hex.view.bookmarks.default_title", "Lesezeichen [0x{0:X} - 0x{1:X}]" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "Noch kein Lesezeichen erstellt. Füge eines hinzu mit Bearbeiten -> Lesezeichen hinzufügen" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "Noch kein Lesezeichen erstellt. Füge eines hinzu mit Bearbeiten -> Lesezeichen erstellen" },
|
||||
{ "hex.view.bookmarks.title.info", "Informationen" },
|
||||
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} bytes)" },
|
||||
{ "hex.view.bookmarks.button.jump", "Springen" },
|
||||
@@ -316,6 +322,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.store.tab.libraries", "Libraries" },
|
||||
{ "hex.view.store.tab.magics", "Magic Files" },
|
||||
{ "hex.view.store.tab.constants", "Konstanten" },
|
||||
{ "hex.view.store.tab.yara", "Yara Rules" },
|
||||
{ "hex.view.store.loading", "Store inhalt wird geladen..." },
|
||||
{ "hex.view.diff.name", "Diffing" },
|
||||
|
||||
@@ -578,11 +585,53 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.tools.wiki_explain.search", "Suchen" },
|
||||
{ "hex.builtin.tools.wiki_explain.results", "Resultate" },
|
||||
{ "hex.builtin.tools.wiki_explain.invalid_response", "Ungültige Antwort von Wikipedia!" },
|
||||
{ "hex.builtin.tools.file_tools", "File Tools" },
|
||||
{ "hex.builtin.tools.file_tools.shredder", "Schredder" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.warning", "Dieses Tool zerstört eine Datei UNWIEDERRUFLICH. Mit Vorsicht verwenden" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.input", "Datei zum schreddern" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.picker", "Öffne Datei zum schreddern" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.fast", "Schneller Modus" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.shredding", "Schreddert..." },
|
||||
{ "hex.builtin.tools.file_tools.shredder.shred", "Schreddern" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.error.open", "Öffnen der ausgewählten Datei fehlgeschlagen" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.success", "Datei erfolgreich geschreddert!" },
|
||||
{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "5¼\" Floppy disk (1200KiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "3½\" Floppy disk (1400KiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Benutzerdefiniert" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.input", "Zu splittende Datei " },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.input", "Zu splittende Datei öffnen" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.output", "Ziel Pfad" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.output", "Ziel Pfad setzen" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.splitting", "Splittet..." },
|
||||
{ "hex.builtin.tools.file_tools.splitter.split", "Splitten" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.error.open", "Öffnen der ausgewählten Datei fehlgeschlagen" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.error.size", "Datei ist kleiner als Zielgrösse" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.error.create", "Erstellen der Teildatei {0} fehlgeschlagen" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.success", "Datei erfolgreich gesplittet!" },
|
||||
{ "hex.builtin.tools.file_tools.combiner", "Kombinierer" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.add", "Hinzufügen..." },
|
||||
{ "hex.builtin.tools.file_tools.combiner.add.picker", "Datei hinzufügen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.delete", "Entfernen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.clear", "Alle entfernen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.output", "Zieldatei " },
|
||||
{ "hex.builtin.tools.file_tools.combiner.output.picker", "Ziel Pfad setzen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.combining", "Kombiniert..." },
|
||||
{ "hex.builtin.tools.file_tools.combiner.combine", "Kombinieren" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Erstellen der Zieldatei fehlgeschlagen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.open_input", "Öffnen der Inputdatei {0} fehlgeschlagen" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.success", "Dateien erfolgreich kombiniert!" },
|
||||
|
||||
{ "hex.builtin.setting.imhex", "ImHex" },
|
||||
{ "hex.builtin.setting.imhex.recent_files", "Kürzlich geöffnete Dateien" },
|
||||
{ "hex.builtin.setting.general", "Allgemein" },
|
||||
{ "hex.builtin.setting.general.show_tips", "Tipps beim start anzeigen" },
|
||||
{ "hex.builtin.setting.general.auto_load_patterns", "Unterstützte Pattern automatisch laden" },
|
||||
{ "hex.builtin.setting.interface", "Aussehen" },
|
||||
{ "hex.builtin.setting.interface.color", "Farbthema" },
|
||||
{ "hex.builtin.setting.interface.color.system", "System" },
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.decimal", "Decimal" },
|
||||
{ "hex.common.hexadecimal", "Hexadecimal" },
|
||||
{ "hex.common.octal", "Octal" },
|
||||
{ "hex.common.info", "Information" },
|
||||
{ "hex.common.error", "Error" },
|
||||
{ "hex.common.fatal", "Fatal Error" },
|
||||
{ "hex.common.address", "Address" },
|
||||
@@ -79,10 +80,15 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.dont_show_again", "Don't show again" },
|
||||
{ "hex.common.link", "Link" },
|
||||
{ "hex.common.file", "File" },
|
||||
{ "hex.common.open", "Open" },
|
||||
{ "hex.common.browse", "Browse..." },
|
||||
|
||||
{ "hex.message.yara_rule_added", "Yara rule added!" },
|
||||
{ "hex.message.magic_db_added", "Magic database added!" },
|
||||
|
||||
{ "hex.view.bookmarks.name", "Bookmarks" },
|
||||
{ "hex.view.bookmarks.default_title", "Bookmark [0x{0:X} - 0x{1:X}]" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "No bookmarks created yet. Add one with Edit -> Add Bookmark" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "No bookmarks created yet. Add one with Edit -> Create Bookmark" },
|
||||
{ "hex.view.bookmarks.title.info", "Information" },
|
||||
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} bytes)" },
|
||||
{ "hex.view.bookmarks.button.jump", "Jump to" },
|
||||
@@ -316,6 +322,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.store.tab.libraries", "Libraries" },
|
||||
{ "hex.view.store.tab.magics", "Magic Files" },
|
||||
{ "hex.view.store.tab.constants", "Constants" },
|
||||
{ "hex.view.store.tab.yara", "Yara Rules" },
|
||||
{ "hex.view.store.loading", "Loading store content..." },
|
||||
{ "hex.view.diff.name", "Diffing" },
|
||||
|
||||
@@ -579,11 +586,53 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.tools.wiki_explain.search", "Search" },
|
||||
{ "hex.builtin.tools.wiki_explain.results", "Results" },
|
||||
{ "hex.builtin.tools.wiki_explain.invalid_response", "Invalid response from Wikipedia!" },
|
||||
{ "hex.builtin.tools.file_tools", "File Tools" },
|
||||
{ "hex.builtin.tools.file_tools.shredder", "Shredder" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.warning", "This tool IRRECOVERABLY destroys a file. Use with caution" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.input", "File to shred " },
|
||||
{ "hex.builtin.tools.file_tools.shredder.picker", "Open File to Shred" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.fast", "Fast Mode" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.shredding", "Shredding..." },
|
||||
{ "hex.builtin.tools.file_tools.shredder.shred", "Shred" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.error.open", "Failed to open selected file!" },
|
||||
{ "hex.builtin.tools.file_tools.shredder.success", "Shredded successfully!" },
|
||||
{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "5¼\" Floppy disk (1200KiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "3½\" Floppy disk (1400KiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Custom" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.input", "File to split " },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.input", "Open File to split" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.output", "Output path " },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.output", "Set base path" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.splitting", "Splitting..." },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.split", "Split" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.error.open", "Failed to open selected file!" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.error.size", "File is smaller than part size" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.error.create", "Failed to create part file {0}" },
|
||||
{ "hex.builtin.tools.file_tools.splitter.picker.success", "File split successfully!" },
|
||||
{ "hex.builtin.tools.file_tools.combiner", "Combiner" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.add", "Add..." },
|
||||
{ "hex.builtin.tools.file_tools.combiner.add.picker", "Add file" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.delete", "Delete" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.clear", "Clear" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.output", "Output file " },
|
||||
{ "hex.builtin.tools.file_tools.combiner.output.picker", "Set output base path" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.combining", "Combining..." },
|
||||
{ "hex.builtin.tools.file_tools.combiner.combine", "Combine" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Failed to create output file" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.open_input", "Failed to open input file {0}" },
|
||||
{ "hex.builtin.tools.file_tools.combiner.success", "Files combined successfully!" },
|
||||
|
||||
{ "hex.builtin.setting.imhex", "ImHex" },
|
||||
{ "hex.builtin.setting.imhex.recent_files", "Recent Files" },
|
||||
{ "hex.builtin.setting.general", "General" },
|
||||
{ "hex.builtin.setting.general.show_tips", "Show tips on startup" },
|
||||
{ "hex.builtin.setting.general.auto_load_patterns", "Auto-load supported pattern" },
|
||||
{ "hex.builtin.setting.interface", "Interface" },
|
||||
{ "hex.builtin.setting.interface.color", "Color theme" },
|
||||
{ "hex.builtin.setting.interface.color.system", "System" },
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.decimal", "Decimale" },
|
||||
{ "hex.common.hexadecimal", "Esadecimale" },
|
||||
{ "hex.common.octal", "Ottale" },
|
||||
//{ "hex.common.info", "Information" },
|
||||
{ "hex.common.error", "Errore" },
|
||||
{ "hex.common.fatal", "Errore Fatale" },
|
||||
{ "hex.common.address", "Indirizzo" },
|
||||
@@ -78,10 +79,15 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.dont_show_again", "Non mostrare di nuovo" },
|
||||
{ "hex.common.link", "Link" },
|
||||
{ "hex.common.file", "File" },
|
||||
//{ "hex.common.open", "Open" },
|
||||
//{ "hex.common.browse", "Browse..." },
|
||||
|
||||
//{ "hex.message.yara_rule_added", "Yara rule added!" },
|
||||
//{ "hex.message.magic_db_added", "Magic database added!" },
|
||||
|
||||
{ "hex.view.bookmarks.name", "Segnalibri" },
|
||||
{ "hex.view.bookmarks.default_title", "Segnalibro [0x{0:X} - 0x{1:X}]" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "Non è stato creato alcun segnalibro. Aggiungine uno andando su Modifica -> Aggiungi Segnalibro" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "Non è stato creato alcun segnalibro. Aggiungine uno andando su Modifica -> Crea Segnalibro" },
|
||||
{ "hex.view.bookmarks.title.info", "Informazioni" },
|
||||
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} bytes)" },
|
||||
{ "hex.view.bookmarks.button.jump", "Vai a" },
|
||||
@@ -315,6 +321,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.store.tab.libraries", "Librerie" },
|
||||
{ "hex.view.store.tab.magics", "File Magici" },
|
||||
{ "hex.view.store.tab.constants", "Costanti" },
|
||||
{ "hex.view.store.tab.yara", "Regole di Yara" },
|
||||
{ "hex.view.store.loading", "Caricamento del content store..." },
|
||||
//{ "hex.view.diff.name", "Diffing" },
|
||||
|
||||
@@ -577,11 +584,53 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.tools.wiki_explain.search", "Cerca" },
|
||||
{ "hex.builtin.tools.wiki_explain.results", "Risultati" },
|
||||
{ "hex.builtin.tools.wiki_explain.invalid_response", "Risposta non valida da Wikipedia!" },
|
||||
//{ "hex.builtin.tools.file_tools", "File Tools" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder", "Shredder" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.warning", "This tool IRRECOVERABLY destroys a file. Use with caution" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.input", "File to shred " },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.picker", "Open File to Shred" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.fast", "Fast Mode" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.shredding", "Shredding..." },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.shred", "Shred" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.error.open", "Failed to open selected file!" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.success", "Shredded successfully!" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "5¼\" Floppy disk (1200KiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "3½\" Floppy disk (1400KiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Custom" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.input", "File to split " },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.input", "Open File to split" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.output", "Output path " },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.output", "Set base path" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.splitting", "Splitting..." },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.split", "Split" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.error.open", "Failed to open selected file!" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.error.size", "File is smaller than part size" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.error.create", "Failed to create part file {0}" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.success", "File split successfully!" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner", "Combiner" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.add", "Add..." },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.add.picker", "Add file" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.delete", "Delete" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.clear", "Clear" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.output", "Output file " },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.output.picker", "Set output base path" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.combining", "Combining..." },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.combine", "Combine" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Failed to create output file" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.open_input", "Failed to open input file {0}" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.success", "Files combined successfully!" },
|
||||
|
||||
{ "hex.builtin.setting.imhex", "ImHex" },
|
||||
{ "hex.builtin.setting.imhex.recent_files", "File recenti" },
|
||||
{ "hex.builtin.setting.general", "Generali" },
|
||||
{ "hex.builtin.setting.general.show_tips", "Mostra consigli all'avvio" },
|
||||
//{ "hex.builtin.setting.general.auto_load_patterns", "Auto-load supported pattern" },
|
||||
{ "hex.builtin.setting.interface", "Interfaccia" },
|
||||
{ "hex.builtin.setting.interface.color", "Colore del Tema" },
|
||||
{ "hex.builtin.setting.interface.color.system", "Sistema" },
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.decimal", "十进制" },
|
||||
{ "hex.common.hexadecimal", "十六进制" },
|
||||
{ "hex.common.octal", "八进制" },
|
||||
//{ "hex.common.info", "Information" },
|
||||
{ "hex.common.error", "错误" },
|
||||
{ "hex.common.fatal", "致命错误" },
|
||||
{ "hex.common.address", "地址" },
|
||||
@@ -79,10 +80,15 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.common.dont_show_again", "不要再次显示" },
|
||||
{ "hex.common.link", "链接" },
|
||||
{ "hex.common.file", "文件" },
|
||||
//{ "hex.common.open", "Open" },
|
||||
//{ "hex.common.browse", "Browse..." },
|
||||
|
||||
//{ "hex.message.yara_rule_added", "Yara rule added!" },
|
||||
//{ "hex.message.magic_db_added", "Magic database added!" },
|
||||
|
||||
{ "hex.view.bookmarks.name", "书签" },
|
||||
{ "hex.view.bookmarks.default_title", "书签 [0x{0:X} - 0x{1:X}]" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "空空如也。通过 编辑->添加书签 添加一个" },
|
||||
{ "hex.view.bookmarks.no_bookmarks", "空空如也。通过 编辑->添加书签" },
|
||||
{ "hex.view.bookmarks.title.info", "信息" },
|
||||
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} 字节)" },
|
||||
{ "hex.view.bookmarks.button.jump", "转到" },
|
||||
@@ -316,7 +322,8 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.view.store.tab.libraries", "库" },
|
||||
{ "hex.view.store.tab.magics", "魔术数据库" },
|
||||
{ "hex.view.store.tab.constants", "常量" },
|
||||
{ "hex.view.store.loading", "正在加载仓库内容..." },
|
||||
{ "hex.view.store.tab.yara", "Yara规则" },
|
||||
{ "hex.view.store.loading", "正在加载仓库内容..." },
|
||||
//{ "hex.view.diff.name", "Diffing" },
|
||||
|
||||
/* Builtin plugin features */
|
||||
@@ -579,11 +586,53 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.tools.wiki_explain.search", "搜索" },
|
||||
{ "hex.builtin.tools.wiki_explain.results", "结果" },
|
||||
{ "hex.builtin.tools.wiki_explain.invalid_response", "接收到来自Wikipedia的无效响应!" },
|
||||
//{ "hex.builtin.tools.file_tools", "File Tools" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder", "Shredder" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.warning", "This tool IRRECOVERABLY destroys a file. Use with caution" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.input", "File to shred " },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.picker", "Open File to Shred" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.fast", "Fast Mode" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.shredding", "Shredding..." },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.shred", "Shred" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.error.open", "Failed to open selected file!" },
|
||||
//{ "hex.builtin.tools.file_tools.shredder.success", "Shredded successfully!" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "5¼\" Floppy disk (1200KiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "3½\" Floppy disk (1400KiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Custom" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.input", "File to split " },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.input", "Open File to split" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.output", "Output path " },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.output", "Set base path" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.splitting", "Splitting..." },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.split", "Split" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.error.open", "Failed to open selected file!" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.error.size", "File is smaller than part size" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.error.create", "Failed to create part file {0}" },
|
||||
//{ "hex.builtin.tools.file_tools.splitter.picker.success", "File split successfully!" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner", "Combiner" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.add", "Add..." },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.add.picker", "Add file" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.delete", "Delete" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.clear", "Clear" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.output", "Output file " },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.output.picker", "Set output base path" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.combining", "Combining..." },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.combine", "Combine" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Failed to create output file" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.open_input", "Failed to open input file {0}" },
|
||||
//{ "hex.builtin.tools.file_tools.combiner.success", "Files combined successfully!" },
|
||||
|
||||
{ "hex.builtin.setting.imhex", "ImHex" },
|
||||
{ "hex.builtin.setting.imhex.recent_files", "最近文件" },
|
||||
{ "hex.builtin.setting.general", "通用" },
|
||||
{ "hex.builtin.setting.general.show_tips", "在启动时显示每日提示" },
|
||||
//{ "hex.builtin.setting.general.auto_load_patterns", "Auto-load supported pattern" },
|
||||
{ "hex.builtin.setting.interface", "界面" },
|
||||
{ "hex.builtin.setting.interface.color", "颜色主题" },
|
||||
{ "hex.builtin.setting.interface.color.system", "跟随系统" },
|
||||
|
||||
@@ -5,33 +5,53 @@ set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/ImGui ${CMAKE_CURRENT_BINARY_DIR}/external/ImGui)
|
||||
|
||||
if(NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nlohmann_json ${CMAKE_CURRENT_BINARY_DIR}/external/nlohmann_json)
|
||||
else()
|
||||
find_package(nlohmann_json 3.10.2 REQUIRED)
|
||||
endif()
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog EXCLUDE_FROM_ALL)
|
||||
if(NOT USE_SYSTEM_FMT)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/fmt ${CMAKE_CURRENT_BINARY_DIR}/external/fmt)
|
||||
else()
|
||||
find_package(fmt 8.0.0 REQUIRED)
|
||||
endif()
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/microtar ${CMAKE_CURRENT_BINARY_DIR}/external/microtar EXCLUDE_FROM_ALL)
|
||||
|
||||
set(XDGPP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../external/xdgpp")
|
||||
set(CMAKE_USE_MBEDTLS ON)
|
||||
set(BUILD_CURL_EXE OFF)
|
||||
set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
|
||||
|
||||
if(NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nlohmann_json ${CMAKE_CURRENT_BINARY_DIR}/external/nlohmann_json)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
|
||||
else()
|
||||
find_package(nlohmann_json 3.10.2 REQUIRED)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_FMT)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/fmt ${CMAKE_CURRENT_BINARY_DIR}/external/fmt)
|
||||
set(FMT_LIBRARIES fmt-header-only)
|
||||
else()
|
||||
find_package(fmt 8.0.0 REQUIRED)
|
||||
set(FMT_LIBRARIES fmt::fmt)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_CURL)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/curl ${CMAKE_CURRENT_BINARY_DIR}/external/curl EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libcurl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(LIBCURL_LIBRARIES libcurl)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.78.0)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/llvm ${CMAKE_CURRENT_BINARY_DIR}/external/llvm EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
find_package(LLVM REQUIRED Demangle)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_YARA)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/yara ${CMAKE_CURRENT_BINARY_DIR}/external/yara EXCLUDE_FROM_ALL)
|
||||
set(YARA_LIBRARIES libyara)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
@@ -78,38 +98,17 @@ if (APPLE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/paths_mac.mm include/hex/helpers/file.hpp)
|
||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/paths_mac.mm)
|
||||
endif ()
|
||||
|
||||
add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
|
||||
|
||||
target_include_directories(libimhex PUBLIC include ${MBEDTLS_INCLUDE_DIR} ${XDGPP_INCLUDE_DIRS})
|
||||
|
||||
if (USE_SYSTEM_FMT)
|
||||
target_include_directories(libimhex PUBLIC include ${FMT_INCLUDE_DIRS})
|
||||
endif()
|
||||
if (USE_SYSTEM_CURL)
|
||||
target_include_directories(libimhex PUBLIC include ${CURL_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR})
|
||||
target_include_directories(libimhex PUBLIC include ${MBEDTLS_INCLUDE_DIR} ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${Python_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS})
|
||||
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
|
||||
|
||||
if (APPLE)
|
||||
find_library(FOUNDATION NAMES Foundation)
|
||||
target_link_libraries(libimhex PUBLIC imgui nlohmann_json mbedcrypto ${FOUNDATION} nfd fmt-header-only libcurl magic)
|
||||
else ()
|
||||
target_link_libraries(libimhex PUBLIC imgui nlohmann_json mbedcrypto nfd magic)
|
||||
|
||||
if (NOT USE_SYSTEM_FMT)
|
||||
target_link_libraries(libimhex PUBLIC fmt-header-only)
|
||||
else()
|
||||
target_link_libraries(libimhex PUBLIC fmt)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_CURL)
|
||||
target_link_libraries(libimhex PUBLIC libcurl)
|
||||
else()
|
||||
target_link_libraries(libimhex PUBLIC curl)
|
||||
endif()
|
||||
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PUBLIC imgui nfd magic capstone LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES})
|
||||
|
||||
@@ -111,11 +111,12 @@ namespace hex {
|
||||
EVENT_DEF(RequestOpenWindow, std::string);
|
||||
EVENT_DEF(RequestSelectionChange, Region);
|
||||
EVENT_DEF(RequestAddBookmark, ImHexApi::Bookmarks::Entry);
|
||||
EVENT_DEF(RequestAppendPatternLanguageCode, std::string);
|
||||
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
|
||||
EVENT_DEF(RequestChangeWindowTitle, std::string);
|
||||
EVENT_DEF(RequestCloseImHex, bool);
|
||||
EVENT_DEF(RequestOpenFile, std::string);
|
||||
EVENT_DEF(RequestChangeTheme, u32);
|
||||
EVENT_DEF(RequestOpenPopup, std::string);
|
||||
|
||||
EVENT_DEF(QuerySelection, Region&);
|
||||
|
||||
|
||||
@@ -30,9 +30,10 @@ namespace hex {
|
||||
|
||||
~File();
|
||||
|
||||
bool isValid() const { return this->m_file != nullptr; }
|
||||
[[nodiscard]] bool isValid() const { return this->m_file != nullptr; }
|
||||
|
||||
void seek(u64 offset);
|
||||
void close();
|
||||
|
||||
size_t readBuffer(u8 *buffer, size_t size);
|
||||
std::vector<u8> readBytes(size_t numBytes = 0);
|
||||
@@ -42,13 +43,18 @@ namespace hex {
|
||||
void write(const std::vector<u8> &bytes);
|
||||
void write(const std::string &string);
|
||||
|
||||
size_t getSize() const;
|
||||
[[nodiscard]] size_t getSize() const;
|
||||
void setSize(u64 size);
|
||||
|
||||
void flush();
|
||||
void remove();
|
||||
|
||||
auto getHandle() { return this->m_file; }
|
||||
const std::string& getPath() { return this->m_path; }
|
||||
|
||||
private:
|
||||
FILE *m_file;
|
||||
std::string m_path;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -8,12 +8,12 @@ namespace hex::literals {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
constexpr static inline unsigned long long operator ""_kiB(unsigned long long kiB) noexcept {
|
||||
constexpr static inline unsigned long long operator ""_KiB(unsigned long long kiB) noexcept {
|
||||
return operator ""_Bytes(kiB * 1024);
|
||||
}
|
||||
|
||||
constexpr static inline unsigned long long operator ""_MiB(unsigned long long MiB) noexcept {
|
||||
return operator ""_kiB(MiB * 1024);
|
||||
return operator ""_KiB(MiB * 1024);
|
||||
}
|
||||
|
||||
constexpr static inline unsigned long long operator ""_GiB(unsigned long long GiB) noexcept {
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace hex {
|
||||
static std::vector<ContentRegistry::Tools::Entry> toolsEntries;
|
||||
static std::vector<ContentRegistry::DataInspector::Entry> dataInspectorEntries;
|
||||
static u32 patternPaletteOffset;
|
||||
static std::string errorPopupMessage;
|
||||
static std::string popupMessage;
|
||||
static std::list<ImHexApi::Bookmarks::Entry> bookmarkEntries;
|
||||
static std::vector<pl::PatternData*> patternData;
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace hex {
|
||||
Folder
|
||||
};
|
||||
|
||||
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback);
|
||||
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback, const std::string &defaultPath = {});
|
||||
|
||||
float float16ToFloat32(u16 float16);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <map>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <ranges>
|
||||
|
||||
#include <hex/pattern_language/ast_node_base.hpp>
|
||||
|
||||
@@ -202,25 +203,25 @@ namespace hex::pl {
|
||||
case Token::Operator::BitNot:
|
||||
return new ASTNodeLiteral(bitNot(left, right));
|
||||
case Token::Operator::BoolEquals:
|
||||
return new ASTNodeLiteral(left == right);
|
||||
return new ASTNodeLiteral(bool(left == right));
|
||||
case Token::Operator::BoolNotEquals:
|
||||
return new ASTNodeLiteral(left != right);
|
||||
return new ASTNodeLiteral(bool(left != right));
|
||||
case Token::Operator::BoolGreaterThan:
|
||||
return new ASTNodeLiteral(left > right);
|
||||
return new ASTNodeLiteral(bool(left > right));
|
||||
case Token::Operator::BoolLessThan:
|
||||
return new ASTNodeLiteral(left < right);
|
||||
return new ASTNodeLiteral(bool(left < right));
|
||||
case Token::Operator::BoolGreaterThanOrEquals:
|
||||
return new ASTNodeLiteral(left >= right);
|
||||
return new ASTNodeLiteral(bool(left >= right));
|
||||
case Token::Operator::BoolLessThanOrEquals:
|
||||
return new ASTNodeLiteral(left <= right);
|
||||
return new ASTNodeLiteral(bool(left <= right));
|
||||
case Token::Operator::BoolAnd:
|
||||
return new ASTNodeLiteral(left && right);
|
||||
return new ASTNodeLiteral(bool(left && right));
|
||||
case Token::Operator::BoolXor:
|
||||
return new ASTNodeLiteral(left && !right || !left && right);
|
||||
return new ASTNodeLiteral(bool(left && !right || !left && right));
|
||||
case Token::Operator::BoolOr:
|
||||
return new ASTNodeLiteral(left || right);
|
||||
return new ASTNodeLiteral(bool(left || right));
|
||||
case Token::Operator::BoolNot:
|
||||
return new ASTNodeLiteral(!right);
|
||||
return new ASTNodeLiteral(bool(!right));
|
||||
default:
|
||||
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this);
|
||||
}
|
||||
@@ -315,7 +316,7 @@ namespace hex::pl {
|
||||
else if (Token::isFloatingPoint(this->m_type))
|
||||
pattern = new PatternDataFloat(offset, size);
|
||||
else if (this->m_type == Token::ValueType::Boolean)
|
||||
pattern = new PatternDataBoolean(offset, size);
|
||||
pattern = new PatternDataBoolean(offset);
|
||||
else if (this->m_type == Token::ValueType::Character)
|
||||
pattern = new PatternDataCharacter(offset);
|
||||
else if (this->m_type == Token::ValueType::Character16)
|
||||
@@ -324,6 +325,8 @@ namespace hex::pl {
|
||||
pattern = new PatternDataPadding(offset, 1);
|
||||
else if (this->m_type == Token::ValueType::String)
|
||||
pattern = new PatternDataString(offset, 1);
|
||||
else if (this->m_type == Token::ValueType::Auto)
|
||||
return { nullptr };
|
||||
else
|
||||
LogConsole::abortEvaluation("invalid built-in type", this);
|
||||
|
||||
@@ -343,17 +346,10 @@ namespace hex::pl {
|
||||
|
||||
ASTNodeTypeDecl(const ASTNodeTypeDecl& other) : ASTNode(other), Attributable(other) {
|
||||
this->m_name = other.m_name;
|
||||
if (other.m_type != nullptr)
|
||||
this->m_type = other.m_type->clone();
|
||||
else
|
||||
this->m_type = nullptr;
|
||||
this->m_type = other.m_type;
|
||||
this->m_endian = other.m_endian;
|
||||
}
|
||||
|
||||
~ASTNodeTypeDecl() override {
|
||||
delete this->m_type;
|
||||
}
|
||||
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeTypeDecl(*this);
|
||||
}
|
||||
@@ -371,6 +367,9 @@ namespace hex::pl {
|
||||
auto patterns = this->m_type->createPatterns(evaluator);
|
||||
|
||||
for (auto &pattern : patterns) {
|
||||
if (pattern == nullptr)
|
||||
continue;
|
||||
|
||||
if (!this->m_name.empty())
|
||||
pattern->setTypeName(this->m_name);
|
||||
pattern->setEndian(this->m_endian.value_or(evaluator->getDefaultEndian()));
|
||||
@@ -482,6 +481,9 @@ namespace hex::pl {
|
||||
|
||||
ASTNodeWhileStatement(const ASTNodeWhileStatement &other) : ASTNode(other) {
|
||||
this->m_condition = other.m_condition->clone();
|
||||
|
||||
for (auto &statement : other.m_body)
|
||||
this->m_body.push_back(statement->clone());
|
||||
}
|
||||
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
@@ -570,6 +572,14 @@ namespace hex::pl {
|
||||
pattern->setComment(*value);
|
||||
} else if (name == "hidden" && noValue()) {
|
||||
pattern->setHidden(true);
|
||||
} else if (name == "inline" && noValue()) {
|
||||
auto inlinable = dynamic_cast<Inlinable*>(pattern);
|
||||
|
||||
if (inlinable == nullptr)
|
||||
LogConsole::abortEvaluation("inline attribute can only be applied to nested types", node);
|
||||
else
|
||||
inlinable->setInlined(true);
|
||||
|
||||
} else if (name == "format" && requiresValue()) {
|
||||
auto functions = evaluator->getCustomFunctions();
|
||||
if (!functions.contains(*value))
|
||||
@@ -579,7 +589,41 @@ namespace hex::pl {
|
||||
if (function.parameterCount != 1)
|
||||
LogConsole::abortEvaluation("formatter function needs exactly one parameter", node);
|
||||
|
||||
pattern->setFormatterFunction(function, evaluator);
|
||||
pattern->setEvaluator(evaluator);
|
||||
pattern->setFormatterFunction(function);
|
||||
} else if (name == "transform" && requiresValue()) {
|
||||
auto functions = evaluator->getCustomFunctions();
|
||||
if (!functions.contains(*value))
|
||||
LogConsole::abortEvaluation(hex::format("cannot find transform function '{}'", *value), node);
|
||||
|
||||
const auto &function = functions[*value];
|
||||
if (function.parameterCount != 1)
|
||||
LogConsole::abortEvaluation("transform function needs exactly one parameter", node);
|
||||
|
||||
pattern->setEvaluator(evaluator);
|
||||
pattern->setTransformFunction(function);
|
||||
} else if (name == "pointer_base" && requiresValue()) {
|
||||
auto functions = evaluator->getCustomFunctions();
|
||||
if (!functions.contains(*value))
|
||||
LogConsole::abortEvaluation(hex::format("cannot find pointer base function '{}'", *value), node);
|
||||
|
||||
const auto &function = functions[*value];
|
||||
if (function.parameterCount != 1)
|
||||
LogConsole::abortEvaluation("pointer base function needs exactly one parameter", node);
|
||||
|
||||
if (auto pointerPattern = dynamic_cast<PatternDataPointer*>(pattern)) {
|
||||
u128 value = 0;
|
||||
evaluator->getProvider()->read(pattern->getOffset(), &value, pattern->getSize());
|
||||
|
||||
auto result = function.func(evaluator, { value });
|
||||
|
||||
if (!result.has_value())
|
||||
LogConsole::abortEvaluation("pointer base function did not return a value", node);
|
||||
|
||||
pointerPattern->rebase(Token::literalToUnsigned(result.value()));
|
||||
} else {
|
||||
LogConsole::abortEvaluation("pointer_base attribute may only be applied to a pointer");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -937,13 +981,28 @@ namespace hex::pl {
|
||||
}, offset->getValue());
|
||||
}
|
||||
|
||||
auto offset = evaluator->dataOffset();
|
||||
|
||||
auto sizePattern = this->m_sizeType->createPatterns(evaluator).front();
|
||||
ON_SCOPE_EXIT { delete sizePattern; };
|
||||
|
||||
auto pattern = new PatternDataPointer(evaluator->dataOffset(), sizePattern->getSize());
|
||||
pattern->setPointedAtPattern(this->m_type->createPatterns(evaluator).front());
|
||||
auto pattern = new PatternDataPointer(offset, sizePattern->getSize());
|
||||
pattern->setVariableName(this->m_name);
|
||||
|
||||
offset = evaluator->dataOffset();
|
||||
|
||||
{
|
||||
auto pointedAtPattern = this->m_type->createPatterns(evaluator).front();
|
||||
|
||||
u128 pointerAddress = 0;
|
||||
evaluator->getProvider()->read(pattern->getOffset(), &pointerAddress, pattern->getSize());
|
||||
pointedAtPattern->setOffset(pointerAddress);
|
||||
|
||||
pattern->setPointedAtPattern(pointedAtPattern);
|
||||
}
|
||||
|
||||
evaluator->dataOffset() = offset;
|
||||
|
||||
applyVariableAttributes(evaluator, this, pattern);
|
||||
|
||||
return { pattern };
|
||||
@@ -1010,11 +1069,15 @@ namespace hex::pl {
|
||||
ASTNodeStruct(const ASTNodeStruct &other) : ASTNode(other), Attributable(other) {
|
||||
for (const auto &otherMember : other.getMembers())
|
||||
this->m_members.push_back(otherMember->clone());
|
||||
for (const auto &otherInheritance : other.getInheritance())
|
||||
this->m_inheritance.push_back(otherInheritance->clone());
|
||||
}
|
||||
|
||||
~ASTNodeStruct() override {
|
||||
for (auto &member : this->m_members)
|
||||
delete member;
|
||||
for (auto &inheritance : this->m_inheritance)
|
||||
delete inheritance;
|
||||
}
|
||||
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
@@ -1028,11 +1091,26 @@ namespace hex::pl {
|
||||
std::vector<PatternData*> memberPatterns;
|
||||
|
||||
evaluator->pushScope(pattern, memberPatterns);
|
||||
|
||||
for (auto inheritance : this->m_inheritance) {
|
||||
auto inheritancePatterns = inheritance->createPatterns(evaluator).front();
|
||||
ON_SCOPE_EXIT {
|
||||
delete inheritancePatterns;
|
||||
};
|
||||
|
||||
if (auto structPattern = dynamic_cast<PatternDataStruct*>(inheritancePatterns)) {
|
||||
for (auto member : structPattern->getMembers()) {
|
||||
memberPatterns.push_back(member->clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto member : this->m_members) {
|
||||
for (auto &memberPattern : member->createPatterns(evaluator)) {
|
||||
memberPatterns.push_back(memberPattern);
|
||||
}
|
||||
}
|
||||
|
||||
evaluator->popScope();
|
||||
|
||||
pattern->setMembers(memberPatterns);
|
||||
@@ -1044,8 +1122,12 @@ namespace hex::pl {
|
||||
[[nodiscard]] const std::vector<ASTNode*>& getMembers() const { return this->m_members; }
|
||||
void addMember(ASTNode *node) { this->m_members.push_back(node); }
|
||||
|
||||
[[nodiscard]] const std::vector<ASTNode*>& getInheritance() const { return this->m_inheritance; }
|
||||
void addInheritance(ASTNode *node) { this->m_inheritance.push_back(node); }
|
||||
|
||||
private:
|
||||
std::vector<ASTNode*> m_members;
|
||||
std::vector<ASTNode*> m_inheritance;
|
||||
};
|
||||
|
||||
class ASTNodeUnion : public ASTNode, public Attributable {
|
||||
@@ -1250,10 +1332,12 @@ namespace hex::pl {
|
||||
}
|
||||
else
|
||||
evaluator->getProvider()->read(pattern->getOffset(), &value, pattern->getSize());
|
||||
|
||||
value = hex::changeEndianess(value, pattern->getSize(), pattern->getEndian());
|
||||
};
|
||||
|
||||
Token::Literal literal;
|
||||
if (dynamic_cast<PatternDataUnsigned*>(pattern)) {
|
||||
if (dynamic_cast<PatternDataUnsigned*>(pattern) || dynamic_cast<PatternDataEnum*>(pattern)) {
|
||||
u128 value = 0;
|
||||
readValue(value, pattern);
|
||||
literal = value;
|
||||
@@ -1294,8 +1378,10 @@ namespace hex::pl {
|
||||
[&, this](auto &&assignmentValue) { LogConsole::abortEvaluation(hex::format("cannot assign '{}' to string", pattern->getTypeName()), this); }
|
||||
}, literal);
|
||||
}
|
||||
else
|
||||
evaluator->getProvider()->read(pattern->getOffset(), value.data(), pattern->getSize());
|
||||
else {
|
||||
value.resize(pattern->getSize());
|
||||
evaluator->getProvider()->read(pattern->getOffset(), value.data(), value.size());
|
||||
}
|
||||
|
||||
literal = value;
|
||||
} else if (auto bitfieldFieldPattern = dynamic_cast<PatternDataBitfieldField*>(pattern)) {
|
||||
@@ -1306,6 +1392,14 @@ namespace hex::pl {
|
||||
literal = pattern->clone();
|
||||
}
|
||||
|
||||
if (auto transformFunc = pattern->getTransformFunction(); transformFunc.has_value()) {
|
||||
auto result = transformFunc->func(evaluator, { literal });
|
||||
|
||||
if (!result.has_value())
|
||||
LogConsole::abortEvaluation("transform function did not return a value", this);
|
||||
literal = result.value();
|
||||
}
|
||||
|
||||
return new ASTNodeLiteral(literal);
|
||||
}
|
||||
|
||||
@@ -1324,7 +1418,13 @@ namespace hex::pl {
|
||||
if (name == "parent") {
|
||||
scopeIndex--;
|
||||
searchScope = *evaluator->getScope(scopeIndex).scope;
|
||||
currPattern = searchScope.front()->getParent();
|
||||
auto currParent = evaluator->getScope(scopeIndex).parent;
|
||||
|
||||
if (currParent == nullptr)
|
||||
LogConsole::abortEvaluation("no parent available", this);
|
||||
|
||||
currPattern = currParent->clone();
|
||||
continue;
|
||||
} else if (name == "this") {
|
||||
searchScope = *evaluator->getScope(scopeIndex).scope;
|
||||
|
||||
@@ -1337,7 +1437,7 @@ namespace hex::pl {
|
||||
continue;
|
||||
} else {
|
||||
bool found = false;
|
||||
for (const auto &variable : searchScope) {
|
||||
for (const auto &variable : (searchScope | std::views::reverse)) {
|
||||
if (variable->getVariableName() == name) {
|
||||
auto newPattern = variable->clone();
|
||||
delete currPattern;
|
||||
@@ -1411,20 +1511,40 @@ namespace hex::pl {
|
||||
|
||||
class ASTNodeScopeResolution : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeScopeResolution(std::vector<std::string> path) : ASTNode(), m_path(std::move(path)) { }
|
||||
explicit ASTNodeScopeResolution(ASTNode *type, std::string name) : ASTNode(), m_type(type), m_name(std::move(name)) { }
|
||||
|
||||
ASTNodeScopeResolution(const ASTNodeScopeResolution&) = default;
|
||||
ASTNodeScopeResolution(const ASTNodeScopeResolution &other) {
|
||||
this->m_type = other.m_type->clone();
|
||||
this->m_name = other.m_name;
|
||||
}
|
||||
|
||||
~ASTNodeScopeResolution() override {
|
||||
delete this->m_type;
|
||||
}
|
||||
|
||||
[[nodiscard]] ASTNode* clone() const override {
|
||||
return new ASTNodeScopeResolution(*this);
|
||||
}
|
||||
|
||||
const std::vector<std::string>& getPath() {
|
||||
return this->m_path;
|
||||
[[nodiscard]] ASTNode* evaluate(Evaluator *evaluator) const override {
|
||||
auto type = this->m_type->evaluate(evaluator);
|
||||
ON_SCOPE_EXIT { delete type; };
|
||||
|
||||
if (auto enumType = dynamic_cast<ASTNodeEnum*>(type)) {
|
||||
for (auto &[name, value] : enumType->getEntries()) {
|
||||
if (name == this->m_name)
|
||||
return value->evaluate(evaluator);
|
||||
}
|
||||
} else {
|
||||
LogConsole::abortEvaluation("invalid scope resolution. Cannot access this type");
|
||||
}
|
||||
|
||||
LogConsole::abortEvaluation(hex::format("could not find constant '{}'", this->m_name), this);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_path;
|
||||
ASTNode *m_type;
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
class ASTNodeConditionalStatement : public ASTNode {
|
||||
@@ -1455,16 +1575,16 @@ namespace hex::pl {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<PatternData*> createPatterns(Evaluator *evaluator) const override {
|
||||
std::vector<PatternData *> patterns;
|
||||
|
||||
auto &scope = *evaluator->getScope(0).scope;
|
||||
auto &body = evaluateCondition(evaluator) ? this->m_trueBody : this->m_falseBody;
|
||||
|
||||
for (auto &node : body) {
|
||||
auto newPatterns = node->createPatterns(evaluator);
|
||||
patterns.insert(patterns.end(), newPatterns.begin(), newPatterns.end());
|
||||
for (auto &pattern : newPatterns)
|
||||
scope.push_back(pattern->clone());
|
||||
}
|
||||
|
||||
return patterns;
|
||||
return { };
|
||||
}
|
||||
|
||||
[[nodiscard]] ASTNode* getCondition() {
|
||||
@@ -1748,7 +1868,7 @@ namespace hex::pl {
|
||||
class ASTNodeFunctionDefinition : public ASTNode {
|
||||
public:
|
||||
// TODO: Implement this
|
||||
ASTNodeFunctionDefinition(std::string name, std::map<std::string, ASTNode*> params, std::vector<ASTNode*> body)
|
||||
ASTNodeFunctionDefinition(std::string name, std::vector<std::pair<std::string, ASTNode*>> params, std::vector<ASTNode*> body)
|
||||
: m_name(std::move(name)), m_params(std::move(params)), m_body(std::move(body)) {
|
||||
|
||||
}
|
||||
@@ -1758,7 +1878,7 @@ namespace hex::pl {
|
||||
this->m_params = other.m_params;
|
||||
|
||||
for (const auto &[name, type] : other.m_params) {
|
||||
this->m_params.emplace(name, type->clone());
|
||||
this->m_params.emplace_back(name, type->clone());
|
||||
}
|
||||
|
||||
for (auto statement : other.m_body) {
|
||||
@@ -1799,7 +1919,7 @@ namespace hex::pl {
|
||||
|
||||
u32 paramIndex = 0;
|
||||
for (const auto &[name, type] : this->m_params) {
|
||||
ctx->createVariable(name, type);
|
||||
ctx->createVariable(name, type, params[paramIndex]);
|
||||
ctx->setVariable(name, params[paramIndex]);
|
||||
|
||||
paramIndex++;
|
||||
@@ -1822,7 +1942,7 @@ namespace hex::pl {
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::map<std::string, ASTNode*> m_params;
|
||||
std::vector<std::pair<std::string, ASTNode*>> m_params;
|
||||
std::vector<ASTNode*> m_body;
|
||||
};
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace hex::pl {
|
||||
return this->m_stack;
|
||||
}
|
||||
|
||||
void createVariable(const std::string &name, ASTNode *type);
|
||||
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt);
|
||||
|
||||
void setVariable(const std::string &name, const Token::Literal& value);
|
||||
|
||||
|
||||
@@ -93,13 +93,14 @@ namespace hex::pl {
|
||||
ASTNode* parseFunctionStatement();
|
||||
ASTNode* parseFunctionVariableAssignment();
|
||||
ASTNode* parseFunctionReturnStatement();
|
||||
std::vector<ASTNode*> parseStatementBody();
|
||||
ASTNode* parseFunctionConditional();
|
||||
ASTNode* parseFunctionWhileLoop();
|
||||
|
||||
void parseAttribute(Attributable *currNode);
|
||||
ASTNode* parseConditional();
|
||||
ASTNode* parseWhileStatement();
|
||||
ASTNodeTypeDecl* parseType(bool allowString = false);
|
||||
ASTNodeTypeDecl* parseType(bool allowFunctionTypes = false);
|
||||
ASTNode* parseUsingDeclaration();
|
||||
ASTNode* parsePadding();
|
||||
ASTNode* parseMemberVariable(ASTNodeTypeDecl *type);
|
||||
@@ -117,6 +118,8 @@ namespace hex::pl {
|
||||
std::vector<ASTNode*> parseNamespace();
|
||||
std::vector<ASTNode*> parseStatements();
|
||||
|
||||
ASTNodeTypeDecl* addType(const std::string &name, ASTNode *node, std::optional<std::endian> endian = std::nullopt);
|
||||
|
||||
std::vector<ASTNode*> parseTillToken(Token::Type endTokenType, const auto value) {
|
||||
std::vector<ASTNode*> program;
|
||||
auto guard = SCOPE_GUARD {
|
||||
|
||||
@@ -43,6 +43,14 @@ namespace hex::pl {
|
||||
|
||||
}
|
||||
|
||||
class Inlinable {
|
||||
public:
|
||||
[[nodiscard]] bool isInlined() const { return this->m_inlined; }
|
||||
void setInlined(bool inlined) { this->m_inlined = inlined; }
|
||||
private:
|
||||
bool m_inlined = false;
|
||||
};
|
||||
|
||||
class PatternData {
|
||||
public:
|
||||
PatternData(u64 offset, size_t size, u32 color = 0)
|
||||
@@ -91,9 +99,13 @@ namespace hex::pl {
|
||||
[[nodiscard]] std::string getDisplayName() const { return this->m_displayName.value_or(this->m_variableName); }
|
||||
void setDisplayName(const std::string &name) { this->m_displayName = name; }
|
||||
|
||||
void setFormatterFunction(const ContentRegistry::PatternLanguageFunctions::Function &function, Evaluator *evaluator) {
|
||||
this->m_formatterFunction = { function, evaluator };
|
||||
}
|
||||
[[nodiscard]] Evaluator* getEvaluator() const { return this->m_evaluator; }
|
||||
void setEvaluator(Evaluator *evaluator) { this->m_evaluator = evaluator; }
|
||||
|
||||
[[nodiscard]] const auto& getTransformFunction() const { return this->m_transformFunction; }
|
||||
void setTransformFunction(const ContentRegistry::PatternLanguageFunctions::Function &function) { this->m_transformFunction = function; }
|
||||
[[nodiscard]] const auto& getFormatterFunction() const { return this->m_formatterFunction; }
|
||||
void setFormatterFunction(const ContentRegistry::PatternLanguageFunctions::Function &function) { this->m_formatterFunction = function; }
|
||||
|
||||
virtual void createEntry(prv::Provider* &provider) = 0;
|
||||
[[nodiscard]] virtual std::string getFormattedName() const = 0;
|
||||
@@ -239,8 +251,7 @@ namespace hex::pl {
|
||||
if (!this->m_formatterFunction.has_value())
|
||||
ImGui::Text("%s", value.c_str());
|
||||
else {
|
||||
auto &[func, evaluator] = this->m_formatterFunction.value();
|
||||
auto result = func.func(evaluator, { literal });
|
||||
auto result = this->m_formatterFunction->func(this->getEvaluator(), { literal });
|
||||
|
||||
if (result.has_value()) {
|
||||
if (auto displayValue = std::get_if<std::string>(&result.value()); displayValue != nullptr)
|
||||
@@ -274,7 +285,9 @@ namespace hex::pl {
|
||||
std::optional<std::string> m_comment;
|
||||
std::string m_typeName;
|
||||
|
||||
std::optional<std::pair<ContentRegistry::PatternLanguageFunctions::Function, Evaluator*>> m_formatterFunction;
|
||||
Evaluator *m_evaluator = nullptr;
|
||||
std::optional<ContentRegistry::PatternLanguageFunctions::Function> m_formatterFunction;
|
||||
std::optional<ContentRegistry::PatternLanguageFunctions::Function> m_transformFunction;
|
||||
|
||||
PatternData *m_parent;
|
||||
bool m_local = false;
|
||||
@@ -378,7 +391,7 @@ namespace hex::pl {
|
||||
|
||||
void setPointedAtPattern(PatternData *pattern) {
|
||||
this->m_pointedAt = pattern;
|
||||
this->m_pointedAt->setVariableName("*" + this->getDisplayName());
|
||||
this->m_pointedAt->setVariableName(hex::format("*({})", this->getVariableName()));
|
||||
}
|
||||
|
||||
[[nodiscard]] PatternData* getPointedAtPattern() {
|
||||
@@ -390,8 +403,14 @@ namespace hex::pl {
|
||||
*static_cast<const PatternDataPointer*>(&other)->m_pointedAt == *this->m_pointedAt;
|
||||
}
|
||||
|
||||
void rebase(u64 base) {
|
||||
this->m_pointedAt->setOffset((this->m_pointedAt->getOffset() - this->m_pointerBase) + base);
|
||||
this->m_pointerBase = base;
|
||||
}
|
||||
|
||||
private:
|
||||
PatternData *m_pointedAt;
|
||||
u64 m_pointerBase = 0;
|
||||
};
|
||||
|
||||
class PatternDataUnsigned : public PatternData {
|
||||
@@ -620,7 +639,7 @@ namespace hex::pl {
|
||||
[[nodiscard]] bool operator==(const PatternData &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
|
||||
};
|
||||
|
||||
class PatternDataDynamicArray : public PatternData {
|
||||
class PatternDataDynamicArray : public PatternData, public Inlinable {
|
||||
public:
|
||||
PatternDataDynamicArray(u64 offset, size_t size, u32 color = 0)
|
||||
: PatternData(offset, size, color) {
|
||||
@@ -655,34 +674,38 @@ namespace hex::pl {
|
||||
if (this->m_entries.empty())
|
||||
return;
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
bool open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04llX", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_entries[0]->getTypeName().c_str());
|
||||
ImGui::SameLine(0, 0);
|
||||
bool open = true;
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04llX", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_entries[0]->getTypeName().c_str());
|
||||
ImGui::SameLine(0, 0);
|
||||
|
||||
ImGui::TextUnformatted("[");
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextColored(ImColor(0xFF00FF00), "%llu", this->m_entries.size());
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextUnformatted("]");
|
||||
ImGui::TextUnformatted("[");
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextColored(ImColor(0xFF00FF00), "%llu", this->m_entries.size());
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextUnformatted("]");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", "{ ... }");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", "{ ... }");
|
||||
}
|
||||
|
||||
if (open) {
|
||||
for (auto &member : this->m_entries)
|
||||
member->draw(provider);
|
||||
|
||||
ImGui::TreePop();
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -748,7 +771,7 @@ namespace hex::pl {
|
||||
std::vector<PatternData*> m_entries;
|
||||
};
|
||||
|
||||
class PatternDataStaticArray : public PatternData {
|
||||
class PatternDataStaticArray : public PatternData, public Inlinable {
|
||||
public:
|
||||
PatternDataStaticArray(u64 offset, size_t size, u32 color = 0)
|
||||
: PatternData(offset, size, color) {
|
||||
@@ -770,28 +793,32 @@ namespace hex::pl {
|
||||
if (this->getEntryCount() == 0)
|
||||
return;
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
bool open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04llX", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_template->getTypeName().c_str());
|
||||
ImGui::SameLine(0, 0);
|
||||
bool open = true;
|
||||
|
||||
ImGui::TextUnformatted("[");
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextColored(ImColor(0xFF00FF00), "%llu", this->m_entryCount);
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextUnformatted("]");
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04llX", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_template->getTypeName().c_str());
|
||||
ImGui::SameLine(0, 0);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", "{ ... }");
|
||||
ImGui::TextUnformatted("[");
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextColored(ImColor(0xFF00FF00), "%llu", this->m_entryCount);
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextUnformatted("]");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", "{ ... }");
|
||||
}
|
||||
|
||||
if (open) {
|
||||
auto entry = this->m_template->clone();
|
||||
@@ -802,22 +829,24 @@ namespace hex::pl {
|
||||
}
|
||||
delete entry;
|
||||
|
||||
ImGui::TreePop();
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<u32> highlightBytes(size_t offset) override{
|
||||
auto entry = this->m_template->clone();
|
||||
ON_SCOPE_EXIT { delete entry; };
|
||||
|
||||
for (u64 address = this->getOffset(); address < this->getOffset() + this->getSize(); address += this->m_template->getSize()) {
|
||||
entry->setOffset(address);
|
||||
if (auto color = entry->highlightBytes(offset); color.has_value())
|
||||
return color.value();
|
||||
}
|
||||
if (offset < this->getOffset() || offset >= this->getOffset() + this->getSize())
|
||||
return { };
|
||||
|
||||
delete entry;
|
||||
|
||||
return { };
|
||||
auto index = (offset - this->getOffset()) / this->m_template->getSize();
|
||||
entry->setOffset(this->getOffset() + this->m_template->getSize() * index);
|
||||
if (auto color = entry->highlightBytes(offset); color.has_value())
|
||||
return color.value();
|
||||
else
|
||||
return { };
|
||||
}
|
||||
|
||||
std::map<u64, u32> getHighlightedAddresses() override {
|
||||
@@ -879,7 +908,7 @@ namespace hex::pl {
|
||||
size_t m_entryCount;
|
||||
};
|
||||
|
||||
class PatternDataStruct : public PatternData {
|
||||
class PatternDataStruct : public PatternData, public Inlinable {
|
||||
public:
|
||||
PatternDataStruct(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color){
|
||||
}
|
||||
@@ -908,25 +937,30 @@ namespace hex::pl {
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider* &provider) override {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
bool open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04llX", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(ImColor(0xFFD69C56), "struct"); ImGui::SameLine(); ImGui::Text("%s", this->getTypeName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", "{ ... }");
|
||||
bool open = true;
|
||||
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04llX", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(ImColor(0xFFD69C56), "struct"); ImGui::SameLine(); ImGui::Text("%s", this->getTypeName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", "{ ... }");
|
||||
}
|
||||
|
||||
if (open) {
|
||||
for (auto &member : this->m_sortedMembers)
|
||||
member->draw(provider);
|
||||
|
||||
ImGui::TreePop();
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1009,7 +1043,7 @@ namespace hex::pl {
|
||||
std::vector<PatternData*> m_sortedMembers;
|
||||
};
|
||||
|
||||
class PatternDataUnion : public PatternData {
|
||||
class PatternDataUnion : public PatternData, public Inlinable {
|
||||
public:
|
||||
PatternDataUnion(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color) {
|
||||
|
||||
@@ -1039,25 +1073,30 @@ namespace hex::pl {
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider* &provider) override {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
bool open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), std::max(this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1), u64(0)));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04llX", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(ImColor(0xFFD69C56), "union"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
|
||||
bool open = true;
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", "{ ... }");
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), std::max(this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1), u64(0)));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04llX", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(ImColor(0xFFD69C56), "union"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", "{ ... }");
|
||||
}
|
||||
|
||||
if (open) {
|
||||
for (auto &member : this->m_sortedMembers)
|
||||
member->draw(provider);
|
||||
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
@@ -1252,7 +1291,6 @@ namespace hex::pl {
|
||||
std::reverse(value.begin(), value.end());
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", this->getDisplayName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
@@ -1303,7 +1341,7 @@ namespace hex::pl {
|
||||
u8 m_bitOffset, m_bitSize;
|
||||
};
|
||||
|
||||
class PatternDataBitfield : public PatternData {
|
||||
class PatternDataBitfield : public PatternData, public Inlinable {
|
||||
public:
|
||||
PatternDataBitfield(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color) {
|
||||
|
||||
@@ -1330,32 +1368,36 @@ namespace hex::pl {
|
||||
if (this->m_endian == std::endian::little)
|
||||
std::reverse(value.begin(), value.end());
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
bool open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04llX", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(ImColor(0xFFD69C56), "bitfield"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
bool open = true;
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04llX", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(ImColor(0xFFD69C56), "bitfield"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
std::string valueString = "{ ";
|
||||
for (auto i : value)
|
||||
valueString += hex::format("{0:02X} ", i);
|
||||
valueString += "}";
|
||||
std::string valueString = "{ ";
|
||||
for (auto i : value)
|
||||
valueString += hex::format("{0:02X} ", i);
|
||||
valueString += "}";
|
||||
|
||||
ImGui::TextUnformatted(valueString.c_str());
|
||||
ImGui::TextUnformatted(valueString.c_str());
|
||||
}
|
||||
|
||||
if (open) {
|
||||
|
||||
for (auto &field : this->m_fields)
|
||||
field->draw(provider);
|
||||
|
||||
ImGui::TreePop();
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ namespace hex::pl {
|
||||
Float = 0x42,
|
||||
Double = 0x82,
|
||||
String = 0x15,
|
||||
Auto = 0x16,
|
||||
CustomType = 0x00,
|
||||
Padding = 0x1F,
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace hex {
|
||||
|
||||
static void drawCommonInterfaces();
|
||||
|
||||
static void showMessagePopup(const std::string &message);
|
||||
static void showErrorPopup(const std::string &errorMessage);
|
||||
static void showFatalPopup(const std::string &errorMessage);
|
||||
|
||||
@@ -53,10 +54,8 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] const std::string& getUnlocalizedName() const;
|
||||
|
||||
protected:
|
||||
void discardNavigationRequests();
|
||||
|
||||
void confirmButtons(const std::string &textLeft, const std::string &textRight, const std::function<void()> &leftButtonFn, const std::function<void()> &rightButtonFn);
|
||||
static void confirmButtons(const std::string &textLeft, const std::string &textRight, const std::function<void()> &leftButtonFn, const std::function<void()> &rightButtonFn);
|
||||
static void discardNavigationRequests();
|
||||
|
||||
static inline std::string toWindowName(const std::string &unlocalizedName) {
|
||||
return LangEntry(unlocalizedName) + "###" + unlocalizedName;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
File::File(const std::string &path, Mode mode) {
|
||||
File::File(const std::string &path, Mode mode) : m_path(path) {
|
||||
if (mode == File::Mode::Read)
|
||||
this->m_file = fopen64(path.c_str(), "rb");
|
||||
else if (mode == File::Mode::Write)
|
||||
@@ -23,14 +23,20 @@ namespace hex {
|
||||
}
|
||||
|
||||
File::~File() {
|
||||
if (isValid())
|
||||
fclose(this->m_file);
|
||||
this->close();
|
||||
}
|
||||
|
||||
void File::seek(u64 offset) {
|
||||
fseeko64(this->m_file, offset, SEEK_SET);
|
||||
}
|
||||
|
||||
void File::close() {
|
||||
if (isValid()) {
|
||||
fclose(this->m_file);
|
||||
this->m_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
size_t File::readBuffer(u8 *buffer, size_t size) {
|
||||
if (!isValid()) return 0;
|
||||
|
||||
@@ -41,7 +47,7 @@ namespace hex {
|
||||
if (!isValid()) return { };
|
||||
|
||||
std::vector<u8> bytes(numBytes ?: getSize());
|
||||
auto bytesRead = fread(bytes.data(), bytes.size(), 1, this->m_file);
|
||||
auto bytesRead = fread(bytes.data(), 1, bytes.size(), this->m_file);
|
||||
|
||||
bytes.resize(bytesRead);
|
||||
|
||||
@@ -63,7 +69,7 @@ namespace hex {
|
||||
void File::write(const std::vector<u8> &bytes) {
|
||||
if (!isValid()) return;
|
||||
|
||||
fwrite(bytes.data(), bytes.size(), 1, this->m_file);
|
||||
fwrite(bytes.data(), 1, bytes.size(), this->m_file);
|
||||
}
|
||||
|
||||
void File::write(const std::string &string) {
|
||||
@@ -89,4 +95,13 @@ namespace hex {
|
||||
ftruncate64(fileno(this->m_file), size);
|
||||
}
|
||||
|
||||
void File::flush() {
|
||||
fflush(this->m_file);
|
||||
}
|
||||
|
||||
void File::remove() {
|
||||
this->close();
|
||||
std::remove(this->m_path.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -74,7 +74,7 @@ namespace hex::magic {
|
||||
auto magicFiles = getMagicFiles();
|
||||
|
||||
if (magicFiles.has_value()) {
|
||||
magic_t ctx = magic_open(MAGIC_MIME);
|
||||
magic_t ctx = magic_open(MAGIC_MIME_TYPE);
|
||||
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||
|
||||
if (magic_load(ctx, magicFiles->c_str()) == 0)
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace hex {
|
||||
std::vector<ContentRegistry::Tools::Entry> SharedData::toolsEntries;
|
||||
std::vector<ContentRegistry::DataInspector::Entry> SharedData::dataInspectorEntries;
|
||||
u32 SharedData::patternPaletteOffset;
|
||||
std::string SharedData::errorPopupMessage;
|
||||
std::string SharedData::popupMessage;
|
||||
std::list<ImHexApi::Bookmarks::Entry> SharedData::bookmarkEntries;
|
||||
std::vector<pl::PatternData*> SharedData::patternData;
|
||||
|
||||
|
||||
@@ -184,20 +184,20 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback) {
|
||||
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback, const std::string &defaultPath) {
|
||||
NFD::Init();
|
||||
|
||||
nfdchar_t *outPath;
|
||||
nfdresult_t result;
|
||||
switch (mode) {
|
||||
case DialogMode::Open:
|
||||
result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), nullptr);
|
||||
result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
|
||||
break;
|
||||
case DialogMode::Save:
|
||||
result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), nullptr);
|
||||
result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
|
||||
break;
|
||||
case DialogMode::Folder:
|
||||
result = NFD::PickFolder(outPath, nullptr);
|
||||
result = NFD::PickFolder(outPath, defaultPath.c_str());
|
||||
break;
|
||||
default: __builtin_unreachable();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
void Evaluator::createVariable(const std::string &name, ASTNode *type) {
|
||||
void Evaluator::createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value) {
|
||||
auto &variables = *this->getScope(0).scope;
|
||||
for (auto &variable : variables) {
|
||||
if (variable->getVariableName() == name) {
|
||||
@@ -11,7 +11,30 @@ namespace hex::pl {
|
||||
}
|
||||
}
|
||||
|
||||
auto startOffset = this->dataOffset();
|
||||
auto pattern = type->createPatterns(this).front();
|
||||
this->dataOffset() = startOffset;
|
||||
|
||||
if (pattern == nullptr) {
|
||||
// Handle auto variables
|
||||
if (!value.has_value())
|
||||
LogConsole::abortEvaluation("cannot determine type of auto variable", type);
|
||||
|
||||
if (std::get_if<u128>(&*value) != nullptr)
|
||||
pattern = new PatternDataUnsigned(0, sizeof(u128));
|
||||
else if (std::get_if<s128>(&*value) != nullptr)
|
||||
pattern = new PatternDataSigned(0, sizeof(s128));
|
||||
else if (std::get_if<double>(&*value) != nullptr)
|
||||
pattern = new PatternDataFloat(0, sizeof(double));
|
||||
else if (std::get_if<bool>(&*value) != nullptr)
|
||||
pattern = new PatternDataBoolean(0);
|
||||
else if (std::get_if<char>(&*value) != nullptr)
|
||||
pattern = new PatternDataCharacter(0);
|
||||
else if (std::get_if<PatternData*>(&*value) != nullptr)
|
||||
pattern = std::get<PatternData*>(*value)->clone();
|
||||
else if (std::get_if<std::string>(&*value) != nullptr)
|
||||
pattern = new PatternDataString(0, 1);
|
||||
}
|
||||
|
||||
pattern->setVariableName(name);
|
||||
pattern->setOffset(this->getStack().size());
|
||||
@@ -74,7 +97,7 @@ namespace hex::pl {
|
||||
}
|
||||
}, value);
|
||||
|
||||
this->getStack().back() = castedLiteral;
|
||||
this->getStack()[pattern->getOffset()] = castedLiteral;
|
||||
}
|
||||
|
||||
std::optional<std::vector<PatternData*>> Evaluator::evaluate(const std::vector<ASTNode*> &ast) {
|
||||
|
||||
@@ -375,7 +375,7 @@ namespace hex::pl {
|
||||
|
||||
tokens.emplace_back(VALUE_TOKEN(String, Token::Literal(s)));
|
||||
offset += stringSize;
|
||||
} else if (std::isalpha(c)) {
|
||||
} else if (std::isalpha(c) || c == '_') {
|
||||
std::string identifier = matchTillInvalid(&code[offset], [](char c) -> bool { return std::isalnum(c) || c == '_'; });
|
||||
|
||||
// Check for reserved keywords
|
||||
@@ -450,6 +450,8 @@ namespace hex::pl {
|
||||
tokens.emplace_back(TOKEN(ValueType, String));
|
||||
else if (identifier == "padding")
|
||||
tokens.emplace_back(TOKEN(ValueType, Padding));
|
||||
else if (identifier == "auto")
|
||||
tokens.emplace_back(TOKEN(ValueType, Auto));
|
||||
|
||||
// If it's not a keyword and a builtin type, it has to be an identifier
|
||||
|
||||
|
||||
@@ -77,7 +77,10 @@ namespace hex::pl {
|
||||
typeName += "::";
|
||||
continue;
|
||||
} else {
|
||||
return create(new ASTNodeScopeResolution({ typeName, getValue<Token::Identifier>(-1).get() }));
|
||||
if (!this->m_types.contains(typeName))
|
||||
throwParseError(hex::format("cannot access scope of invalid type '{}'", typeName), -1);
|
||||
|
||||
return create(new ASTNodeScopeResolution(this->m_types[typeName]->clone(), getValue<Token::Identifier>(-1).get()));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -115,6 +118,8 @@ namespace hex::pl {
|
||||
ASTNode* Parser::parseFactor() {
|
||||
if (MATCHES(sequence(INTEGER)))
|
||||
return new ASTNodeLiteral(getValue<Token::Literal>(-1));
|
||||
else if (peek(OPERATOR_PLUS) || peek(OPERATOR_MINUS) || peek(OPERATOR_BITNOT) || peek(OPERATOR_BOOLNOT))
|
||||
return this->parseMathematicalExpression();
|
||||
else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN))) {
|
||||
auto node = this->parseMathematicalExpression();
|
||||
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
|
||||
@@ -168,14 +173,11 @@ namespace hex::pl {
|
||||
if (builtinType == nullptr)
|
||||
throwParseError("invalid type used for pointer size", -1);
|
||||
|
||||
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN)))
|
||||
if (!peek(SEPARATOR_ROUNDBRACKETOPEN))
|
||||
throwParseError("expected '(' before cast expression", -1);
|
||||
|
||||
auto node = parseFactor();
|
||||
|
||||
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
|
||||
throwParseError("expected ')' after cast expression", -1);
|
||||
|
||||
return new ASTNodeCast(node, type);
|
||||
} else return parseFactor();
|
||||
}
|
||||
@@ -325,7 +327,7 @@ namespace hex::pl {
|
||||
auto nodeCleanup = SCOPE_GUARD { delete node; };
|
||||
|
||||
while (MATCHES(sequence(OPERATOR_BOOLAND))) {
|
||||
node = create(new ASTNodeMathematicalExpression(node, this->parseBinaryOrExpression(), Token::Operator::BitOr));
|
||||
node = create(new ASTNodeMathematicalExpression(node, this->parseBinaryOrExpression(), Token::Operator::BoolAnd));
|
||||
}
|
||||
|
||||
nodeCleanup.release();
|
||||
@@ -340,7 +342,7 @@ namespace hex::pl {
|
||||
auto nodeCleanup = SCOPE_GUARD { delete node; };
|
||||
|
||||
while (MATCHES(sequence(OPERATOR_BOOLXOR))) {
|
||||
node = create(new ASTNodeMathematicalExpression(node, this->parseBooleanAnd(), Token::Operator::BitOr));
|
||||
node = create(new ASTNodeMathematicalExpression(node, this->parseBooleanAnd(), Token::Operator::BoolXor));
|
||||
}
|
||||
|
||||
nodeCleanup.release();
|
||||
@@ -355,7 +357,7 @@ namespace hex::pl {
|
||||
auto nodeCleanup = SCOPE_GUARD { delete node; };
|
||||
|
||||
while (MATCHES(sequence(OPERATOR_BOOLOR))) {
|
||||
node = create(new ASTNodeMathematicalExpression(node, this->parseBooleanXor(), Token::Operator::BitOr));
|
||||
node = create(new ASTNodeMathematicalExpression(node, this->parseBooleanXor(), Token::Operator::BoolOr));
|
||||
}
|
||||
|
||||
nodeCleanup.release();
|
||||
@@ -422,7 +424,7 @@ namespace hex::pl {
|
||||
|
||||
ASTNode* Parser::parseFunctionDefinition() {
|
||||
const auto &functionName = getValue<Token::Identifier>(-2).get();
|
||||
std::map<std::string, ASTNode*> params;
|
||||
std::vector<std::pair<std::string, ASTNode*>> params;
|
||||
|
||||
// Parse parameter list
|
||||
bool hasParams = !peek(SEPARATOR_ROUNDBRACKETCLOSE);
|
||||
@@ -431,9 +433,9 @@ namespace hex::pl {
|
||||
auto type = parseType(true);
|
||||
|
||||
if (MATCHES(sequence(IDENTIFIER)))
|
||||
params.emplace(getValue<Token::Identifier>(-1).get(), type);
|
||||
params.emplace_back(getValue<Token::Identifier>(-1).get(), type);
|
||||
else {
|
||||
params.emplace(std::to_string(unnamedParamCount), type);
|
||||
params.emplace_back(std::to_string(unnamedParamCount), type);
|
||||
unnamedParamCount++;
|
||||
}
|
||||
|
||||
@@ -531,6 +533,27 @@ namespace hex::pl {
|
||||
return create(new ASTNodeReturnStatement(this->parseMathematicalExpression()));
|
||||
}
|
||||
|
||||
std::vector<ASTNode*> Parser::parseStatementBody() {
|
||||
std::vector<ASTNode*> body;
|
||||
|
||||
auto bodyCleanup = SCOPE_GUARD {
|
||||
for (auto &node : body)
|
||||
delete node;
|
||||
};
|
||||
|
||||
if (MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) {
|
||||
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
|
||||
body.push_back(parseFunctionStatement());
|
||||
}
|
||||
} else {
|
||||
body.push_back(parseFunctionStatement());
|
||||
}
|
||||
|
||||
bodyCleanup.release();
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseFunctionConditional() {
|
||||
auto condition = parseMathematicalExpression();
|
||||
std::vector<ASTNode*> trueBody, falseBody;
|
||||
@@ -543,22 +566,13 @@ namespace hex::pl {
|
||||
delete statement;
|
||||
};
|
||||
|
||||
if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE, SEPARATOR_CURLYBRACKETOPEN))) {
|
||||
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
|
||||
trueBody.push_back(parseFunctionStatement());
|
||||
}
|
||||
} else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
|
||||
trueBody.push_back(parseFunctionStatement());
|
||||
} else
|
||||
throwParseError("expected body of conditional statement");
|
||||
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
|
||||
throwParseError("expected closing ')' after statement head");
|
||||
|
||||
if (MATCHES(sequence(KEYWORD_ELSE, SEPARATOR_CURLYBRACKETOPEN))) {
|
||||
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
|
||||
falseBody.push_back(parseFunctionStatement());
|
||||
}
|
||||
} else if (MATCHES(sequence(KEYWORD_ELSE))) {
|
||||
falseBody.push_back(parseFunctionStatement());
|
||||
}
|
||||
trueBody = parseStatementBody();
|
||||
|
||||
if (MATCHES(sequence(KEYWORD_ELSE)))
|
||||
falseBody = parseStatementBody();
|
||||
|
||||
cleanup.release();
|
||||
|
||||
@@ -575,14 +589,10 @@ namespace hex::pl {
|
||||
delete statement;
|
||||
};
|
||||
|
||||
if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE, SEPARATOR_CURLYBRACKETOPEN))) {
|
||||
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
|
||||
body.push_back(parseFunctionStatement());
|
||||
}
|
||||
} else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
|
||||
body.push_back(parseFunctionStatement());
|
||||
} else
|
||||
throwParseError("expected body of conditional statement");
|
||||
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
|
||||
throwParseError("expected closing ')' after statement head");
|
||||
|
||||
body = parseStatementBody();
|
||||
|
||||
cleanup.release();
|
||||
|
||||
@@ -645,7 +655,7 @@ namespace hex::pl {
|
||||
/* Type declarations */
|
||||
|
||||
// [be|le] <Identifier|u8|u16|u32|u64|u128|s8|s16|s32|s64|s128|float|double|str>
|
||||
ASTNodeTypeDecl* Parser::parseType(bool allowString) {
|
||||
ASTNodeTypeDecl* Parser::parseType(bool allowFunctionTypes) {
|
||||
std::optional<std::endian> endian;
|
||||
|
||||
if (MATCHES(sequence(KEYWORD_LE)))
|
||||
@@ -665,8 +675,12 @@ namespace hex::pl {
|
||||
}
|
||||
else if (MATCHES(sequence(VALUETYPE_ANY))) { // Builtin type
|
||||
auto type = getValue<Token::ValueType>(-1);
|
||||
if (!allowString && type == Token::ValueType::String)
|
||||
throwParseError("cannot use 'str' in this context. Use a character array instead");
|
||||
if (!allowFunctionTypes) {
|
||||
if (type == Token::ValueType::String)
|
||||
throwParseError("cannot use 'str' in this context. Use a character array instead");
|
||||
else if (type == Token::ValueType::Auto)
|
||||
throwParseError("cannot use 'auto' in this context");
|
||||
}
|
||||
|
||||
return create(new ASTNodeTypeDecl({ }, new ASTNodeBuiltinType(type), endian));
|
||||
} else throwParseError("failed to parse type. Expected identifier or builtin type");
|
||||
@@ -678,7 +692,7 @@ namespace hex::pl {
|
||||
auto *type = dynamic_cast<ASTNodeTypeDecl *>(parseType());
|
||||
if (type == nullptr) throwParseError("invalid type used in variable declaration", -1);
|
||||
|
||||
return create(new ASTNodeTypeDecl(name, type, type->getEndian()));
|
||||
return addType(name, type, type->getEndian());
|
||||
}
|
||||
|
||||
// padding[(parseMathematicalExpression)]
|
||||
@@ -701,14 +715,14 @@ namespace hex::pl {
|
||||
auto variableCleanup = SCOPE_GUARD { for (auto var : variables) delete var; };
|
||||
|
||||
do {
|
||||
variables.push_back(create(new ASTNodeVariableDecl(getValue<Token::Identifier>(-1).get(), type->clone())));
|
||||
variables.push_back(create(new ASTNodeVariableDecl(getValue<Token::Identifier>(-1).get(), type)));
|
||||
} while (MATCHES(sequence(SEPARATOR_COMMA, IDENTIFIER)));
|
||||
|
||||
variableCleanup.release();
|
||||
|
||||
return create(new ASTNodeMultiVariableDecl(variables));
|
||||
} else
|
||||
return create(new ASTNodeVariableDecl(getValue<Token::Identifier>(-1).get(), type->clone()));
|
||||
return create(new ASTNodeVariableDecl(getValue<Token::Identifier>(-1).get(), type));
|
||||
}
|
||||
|
||||
// (parseType) Identifier[(parseMathematicalExpression)]
|
||||
@@ -730,7 +744,7 @@ namespace hex::pl {
|
||||
|
||||
sizeCleanup.release();
|
||||
|
||||
return create(new ASTNodeArrayVariableDecl(name, type->clone(), size));
|
||||
return create(new ASTNodeArrayVariableDecl(name, type, size));
|
||||
}
|
||||
|
||||
// (parseType) *Identifier : (parseType)
|
||||
@@ -746,7 +760,7 @@ namespace hex::pl {
|
||||
throwParseError("invalid type used for pointer size", -1);
|
||||
}
|
||||
|
||||
return create(new ASTNodePointerVariableDecl(name, type->clone(), sizeType));
|
||||
return create(new ASTNodePointerVariableDecl(name, type, sizeType));
|
||||
}
|
||||
|
||||
// [(parsePadding)|(parseMemberVariable)|(parseMemberArrayVariable)|(parseMemberPointerVariable)]
|
||||
@@ -758,7 +772,6 @@ namespace hex::pl {
|
||||
// Some kind of variable definition
|
||||
|
||||
auto type = parseType();
|
||||
ON_SCOPE_EXIT { delete type; };
|
||||
|
||||
if (MATCHES(sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN)) && sequence<Not>(SEPARATOR_SQUAREBRACKETOPEN))
|
||||
member = parseMemberArrayVariable(type);
|
||||
@@ -792,9 +805,29 @@ namespace hex::pl {
|
||||
|
||||
// struct Identifier { <(parseMember)...> }
|
||||
ASTNode* Parser::parseStruct() {
|
||||
const auto &typeName = getValue<Token::Identifier>(-1).get();
|
||||
|
||||
const auto structNode = create(new ASTNodeStruct());
|
||||
const auto &typeName = getValue<Token::Identifier>(-2).get();
|
||||
auto structGuard = SCOPE_GUARD { delete structNode; };
|
||||
const auto typeDecl = addType(typeName, structNode);
|
||||
auto structGuard = SCOPE_GUARD { delete structNode; delete typeDecl; };
|
||||
|
||||
if (MATCHES(sequence(OPERATOR_INHERIT, IDENTIFIER))) {
|
||||
// Inheritance
|
||||
|
||||
do {
|
||||
auto inheritedTypeName = getValue<Token::Identifier>(-1).get();
|
||||
if (!this->m_types.contains(inheritedTypeName))
|
||||
throwParseError(hex::format("cannot inherit from unknown type '{}'", inheritedTypeName), -1);
|
||||
|
||||
structNode->addInheritance(this->m_types[inheritedTypeName]->clone());
|
||||
} while (MATCHES(sequence(SEPARATOR_COMMA, IDENTIFIER)));
|
||||
|
||||
} else if (MATCHES(sequence(OPERATOR_INHERIT, VALUETYPE_ANY))) {
|
||||
throwParseError("cannot inherit from builtin type");
|
||||
}
|
||||
|
||||
if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN)))
|
||||
throwParseError("expected '{' after struct definition", -1);
|
||||
|
||||
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
|
||||
structNode->addMember(parseMember());
|
||||
@@ -802,14 +835,16 @@ namespace hex::pl {
|
||||
|
||||
structGuard.release();
|
||||
|
||||
return create(new ASTNodeTypeDecl(typeName, structNode));
|
||||
return typeDecl;
|
||||
}
|
||||
|
||||
// union Identifier { <(parseMember)...> }
|
||||
ASTNode* Parser::parseUnion() {
|
||||
const auto unionNode = create(new ASTNodeUnion());
|
||||
const auto &typeName = getValue<Token::Identifier>(-2).get();
|
||||
auto unionGuard = SCOPE_GUARD { delete unionNode; };
|
||||
|
||||
const auto unionNode = create(new ASTNodeUnion());
|
||||
const auto typeDecl = addType(typeName, unionNode);
|
||||
auto unionGuard = SCOPE_GUARD { delete unionNode; delete typeDecl; };
|
||||
|
||||
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
|
||||
unionNode->addMember(parseMember());
|
||||
@@ -817,7 +852,7 @@ namespace hex::pl {
|
||||
|
||||
unionGuard.release();
|
||||
|
||||
return create(new ASTNodeTypeDecl(typeName, unionNode));
|
||||
return typeDecl;
|
||||
}
|
||||
|
||||
// enum Identifier : (parseType) { <<Identifier|Identifier = (parseMathematicalExpression)[,]>...> }
|
||||
@@ -828,7 +863,8 @@ namespace hex::pl {
|
||||
if (underlyingType->getEndian().has_value()) throwParseError("underlying type may not have an endian specification", -2);
|
||||
|
||||
const auto enumNode = create(new ASTNodeEnum(underlyingType));
|
||||
auto enumGuard = SCOPE_GUARD { delete enumNode; };
|
||||
const auto typeDecl = addType(typeName, enumNode);
|
||||
auto enumGuard = SCOPE_GUARD { delete enumNode; delete typeDecl; };
|
||||
|
||||
if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN)))
|
||||
throwParseError("expected '{' after enum definition", -1);
|
||||
@@ -867,7 +903,7 @@ namespace hex::pl {
|
||||
|
||||
enumGuard.release();
|
||||
|
||||
return create(new ASTNodeTypeDecl(typeName, enumNode));
|
||||
return typeDecl;
|
||||
}
|
||||
|
||||
// bitfield Identifier { <Identifier : (parseMathematicalExpression)[;]...> }
|
||||
@@ -875,7 +911,9 @@ namespace hex::pl {
|
||||
std::string typeName = getValue<Token::Identifier>(-2).get();
|
||||
|
||||
const auto bitfieldNode = create(new ASTNodeBitfield());
|
||||
auto enumGuard = SCOPE_GUARD { delete bitfieldNode; };
|
||||
const auto typeDecl = addType(typeName, bitfieldNode);
|
||||
|
||||
auto enumGuard = SCOPE_GUARD { delete bitfieldNode; delete typeDecl; };
|
||||
|
||||
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
|
||||
if (MATCHES(sequence(IDENTIFIER, OPERATOR_INHERIT))) {
|
||||
@@ -896,7 +934,7 @@ namespace hex::pl {
|
||||
|
||||
enumGuard.release();
|
||||
|
||||
return create(new ASTNodeTypeDecl(typeName, bitfieldNode));
|
||||
return typeDecl;
|
||||
}
|
||||
|
||||
// (parseType) Identifier @ Integer
|
||||
@@ -1028,7 +1066,7 @@ namespace hex::pl {
|
||||
}
|
||||
else if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY))
|
||||
statement = parsePlacement();
|
||||
else if (MATCHES(sequence(KEYWORD_STRUCT, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN)))
|
||||
else if (MATCHES(sequence(KEYWORD_STRUCT, IDENTIFIER)))
|
||||
statement = parseStruct();
|
||||
else if (MATCHES(sequence(KEYWORD_UNION, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN)))
|
||||
statement = parseUnion();
|
||||
@@ -1051,19 +1089,21 @@ namespace hex::pl {
|
||||
// Consume superfluous semicolons
|
||||
while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)));
|
||||
|
||||
if (auto typeDecl = dynamic_cast<ASTNodeTypeDecl*>(statement); typeDecl != nullptr) {
|
||||
auto typeName = getNamespacePrefixedName(typeDecl->getName());
|
||||
|
||||
if (this->m_types.contains(typeName))
|
||||
throwParseError(hex::format("redefinition of type '{}'", typeName));
|
||||
|
||||
typeDecl->setName(typeName);
|
||||
this->m_types.insert({ typeName, typeDecl });
|
||||
}
|
||||
|
||||
return { statement };
|
||||
}
|
||||
|
||||
ASTNodeTypeDecl* Parser::addType(const std::string &name, ASTNode *node, std::optional<std::endian> endian) {
|
||||
auto typeName = getNamespacePrefixedName(name);
|
||||
|
||||
if (this->m_types.contains(typeName))
|
||||
throwParseError(hex::format("redefinition of type '{}'", typeName));
|
||||
|
||||
auto typeDecl = create(new ASTNodeTypeDecl(typeName, node, endian));
|
||||
this->m_types.insert({ typeName, typeDecl });
|
||||
|
||||
return typeDecl;
|
||||
}
|
||||
|
||||
// <(parseNamespace)...> EndOfProgram
|
||||
std::optional<std::vector<ASTNode*>> Parser::parse(const std::vector<Token> &tokens) {
|
||||
this->m_curr = tokens.begin();
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace hex::pl {
|
||||
std::optional<std::string> Preprocessor::preprocess(const std::string& code, bool initialRun) {
|
||||
u32 offset = 0;
|
||||
u32 lineNumber = 1;
|
||||
bool isInString = false;
|
||||
|
||||
if (initialRun) {
|
||||
this->m_defines.clear();
|
||||
@@ -27,6 +28,14 @@ namespace hex::pl {
|
||||
try {
|
||||
bool startOfLine = true;
|
||||
while (offset < code.length()) {
|
||||
if (offset > 0 && code[offset - 1] != '\\' && code[offset] == '\"')
|
||||
isInString = !isInString;
|
||||
else if (isInString) {
|
||||
output += code[offset];
|
||||
offset += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (code[offset] == '#' && startOfLine) {
|
||||
offset += 1;
|
||||
|
||||
|
||||
@@ -24,8 +24,9 @@ namespace hex {
|
||||
}
|
||||
|
||||
void View::drawCommonInterfaces() {
|
||||
if (ImGui::BeginPopupModal("hex.common.error"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text("%s", SharedData::errorPopupMessage.c_str());
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(400, 100) * SharedData::globalScale, ImVec2(600, 300) * SharedData::globalScale);
|
||||
if (ImGui::BeginPopupModal("hex.common.info"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextWrapped("%s", SharedData::popupMessage.c_str());
|
||||
ImGui::NewLine();
|
||||
ImGui::Separator();
|
||||
if (ImGui::Button("hex.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
|
||||
@@ -34,8 +35,20 @@ namespace hex {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(400, 100) * SharedData::globalScale, ImVec2(600, 300) * SharedData::globalScale);
|
||||
if (ImGui::BeginPopupModal("hex.common.error"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextWrapped("%s", SharedData::popupMessage.c_str());
|
||||
ImGui::NewLine();
|
||||
ImGui::Separator();
|
||||
if (ImGui::Button("hex.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(400, 100) * SharedData::globalScale, ImVec2(600, 300) * SharedData::globalScale);
|
||||
if (ImGui::BeginPopupModal("hex.common.fatal"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text("%s", SharedData::errorPopupMessage.c_str());
|
||||
ImGui::TextWrapped("%s", SharedData::popupMessage.c_str());
|
||||
ImGui::NewLine();
|
||||
ImGui::Separator();
|
||||
if (ImGui::Button("hex.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape)) {
|
||||
@@ -47,14 +60,20 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void View::showMessagePopup(const std::string &message) {
|
||||
SharedData::popupMessage = message;
|
||||
|
||||
View::doLater([] { ImGui::OpenPopup("hex.common.info"_lang); });
|
||||
}
|
||||
|
||||
void View::showErrorPopup(const std::string &errorMessage) {
|
||||
SharedData::errorPopupMessage = errorMessage;
|
||||
SharedData::popupMessage = errorMessage;
|
||||
|
||||
View::doLater([] { ImGui::OpenPopup("hex.common.error"_lang); });
|
||||
}
|
||||
|
||||
void View::showFatalPopup(const std::string &errorMessage) {
|
||||
SharedData::errorPopupMessage = errorMessage;
|
||||
SharedData::popupMessage = errorMessage;
|
||||
|
||||
View::doLater([] { ImGui::OpenPopup("hex.common.fatal"_lang); });
|
||||
}
|
||||
@@ -64,11 +83,11 @@ namespace hex {
|
||||
}
|
||||
|
||||
ImVec2 View::getMinSize() {
|
||||
return ImVec2(480, 720);
|
||||
return ImVec2(480, 720) * SharedData::globalScale;
|
||||
}
|
||||
|
||||
ImVec2 View::getMaxSize() {
|
||||
return ImVec2(FLT_MAX, FLT_MAX);
|
||||
return { FLT_MAX, FLT_MAX };
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace hex {
|
||||
|
||||
code += "};\n";
|
||||
|
||||
EventManager::post<RequestAppendPatternLanguageCode>(code);
|
||||
EventManager::post<RequestSetPatternLanguageCode>(code);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,8 @@ namespace hex {
|
||||
ProjectFile::s_hasUnsavedChanged = false;
|
||||
ProjectFile::s_currProjectFilePath = filePath;
|
||||
|
||||
EventManager::post<EventProjectFileLoad>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ using namespace std::literals::chrono_literals;
|
||||
|
||||
namespace hex::init {
|
||||
|
||||
WindowSplash::WindowSplash(int &argc, char **&argv) {
|
||||
WindowSplash::WindowSplash(int &argc, char **&argv) : m_window(nullptr) {
|
||||
SharedData::mainArgc = argc;
|
||||
SharedData::mainArgv = argv;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace hex::init {
|
||||
|
||||
{
|
||||
std::lock_guard guard(this->m_progressMutex);
|
||||
this->m_progress += 1.0F / m_tasks.size();
|
||||
this->m_progress += 1.0F / this->m_tasks.size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,9 +69,7 @@ namespace hex::init {
|
||||
}
|
||||
|
||||
bool WindowSplash::loop() {
|
||||
ImGui::Texture splashTexture;
|
||||
|
||||
splashTexture = ImGui::LoadImageFromMemory(splash, splash_size);
|
||||
ImGui::Texture splashTexture = ImGui::LoadImageFromMemory(splash, splash_size);
|
||||
|
||||
if (splashTexture == nullptr) {
|
||||
log::fatal("Could not load splash screen image!");
|
||||
@@ -168,10 +166,14 @@ namespace hex::init {
|
||||
glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
|
||||
|
||||
if (GLFWmonitor *monitor = glfwGetPrimaryMonitor(); monitor != nullptr) {
|
||||
float xscale, yscale;
|
||||
glfwGetMonitorContentScale(monitor, &xscale, &yscale);
|
||||
float xScale = 0, yScale = 0;
|
||||
glfwGetMonitorContentScale(monitor, &xScale, &yScale);
|
||||
|
||||
SharedData::globalScale = SharedData::fontScale = std::midpoint(xscale, yscale);
|
||||
SharedData::globalScale = SharedData::fontScale = std::midpoint(xScale, yScale);
|
||||
|
||||
if (SharedData::globalScale <= 0) {
|
||||
SharedData::globalScale = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
this->m_window = glfwCreateWindow(640 * SharedData::globalScale, 400 * SharedData::globalScale, "ImHex", nullptr, nullptr);
|
||||
|
||||
@@ -51,7 +51,8 @@ namespace hex::init {
|
||||
if (!releases.body.contains("tag_name") || !releases.body["tag_name"].is_string())
|
||||
return false;
|
||||
|
||||
auto currVersion = "v" + std::string(IMHEX_VERSION).substr(0, 5);
|
||||
auto versionString = std::string(IMHEX_VERSION);
|
||||
auto currVersion = "v" + versionString.substr(0, versionString.find_first_of('-'));
|
||||
auto latestVersion = releases.body["tag_name"].get<std::string_view>();
|
||||
|
||||
if (latestVersion != currVersion)
|
||||
@@ -112,9 +113,11 @@ namespace hex::init {
|
||||
|
||||
std::string fontFile;
|
||||
for (const auto &dir : hex::getPath(ImHexPath::Resources)) {
|
||||
fontFile = dir + "/font.ttf";
|
||||
if (std::filesystem::exists(fontFile))
|
||||
auto path = dir + "/font.ttf";
|
||||
if (std::filesystem::exists(path)) {
|
||||
fontFile = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ImVector<ImWchar> ranges;
|
||||
@@ -145,8 +148,10 @@ namespace hex::init {
|
||||
0
|
||||
};
|
||||
|
||||
if (!std::filesystem::exists(fontFile)) {
|
||||
|
||||
if (fontFile.empty()) {
|
||||
// Load default font
|
||||
|
||||
fonts->Clear();
|
||||
|
||||
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
||||
@@ -155,10 +160,12 @@ namespace hex::init {
|
||||
} else {
|
||||
// Load custom font
|
||||
|
||||
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
||||
cfg.SizePixels = 13.0f * SharedData::fontScale;
|
||||
auto fontSize = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.font_size", 14);
|
||||
|
||||
fonts->AddFontFromFileTTF(fontFile.c_str(), std::floor(14.0f * SharedData::fontScale), &cfg, ranges.Data); // Needs conversion to char for Windows
|
||||
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
||||
cfg.SizePixels = fontSize * SharedData::fontScale;
|
||||
|
||||
fonts->AddFontFromFileTTF(fontFile.c_str(), std::floor(fontSize * SharedData::fontScale), &cfg, ranges.Data); // Needs conversion to char for Windows
|
||||
}
|
||||
|
||||
cfg.MergeMode = true;
|
||||
|
||||
@@ -52,9 +52,12 @@ namespace hex {
|
||||
auto &bookmarks = ImHexApi::Bookmarks::getEntries();
|
||||
|
||||
if (bookmarks.empty()) {
|
||||
ImGui::NewLine();
|
||||
ImGui::Indent(30);
|
||||
ImGui::TextWrapped("%s", static_cast<const char*>("hex.view.bookmarks.no_bookmarks"_lang));
|
||||
std::string text = "hex.view.bookmarks.no_bookmarks"_lang;
|
||||
auto textSize = ImGui::CalcTextSize(text.c_str());
|
||||
auto availableSpace = ImGui::GetContentRegionAvail();
|
||||
|
||||
ImGui::SetCursorPos((availableSpace - textSize) / 2.0F);
|
||||
ImGui::TextUnformatted(text.c_str());
|
||||
}
|
||||
|
||||
u32 id = 1;
|
||||
|
||||
@@ -197,7 +197,6 @@ namespace hex {
|
||||
} else if (name == "Open Project") {
|
||||
hex::openFileBrowser("hex.view.hexeditor.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) {
|
||||
ProjectFile::load(path);
|
||||
EventManager::post<EventProjectFileLoad>();
|
||||
this->getWindowOpenState() = true;
|
||||
});
|
||||
}
|
||||
@@ -309,11 +308,11 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
this->drawSearchPopup();
|
||||
this->drawGotoPopup();
|
||||
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
this->drawSearchPopup();
|
||||
this->drawGotoPopup();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,6 +460,7 @@ namespace hex {
|
||||
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.close"_lang, "", false, providerValid && provider->isAvailable())) {
|
||||
EventManager::post<EventFileUnloaded>();
|
||||
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
||||
providerValid = false;
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.quit"_lang, "", false)) {
|
||||
@@ -472,7 +472,6 @@ namespace hex {
|
||||
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.open_project"_lang, "")) {
|
||||
hex::openFileBrowser("hex.view.hexeditor.menu.file.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) {
|
||||
ProjectFile::load(path);
|
||||
EventManager::post<EventProjectFileLoad>();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -595,12 +594,12 @@ namespace hex {
|
||||
|
||||
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.search"_lang, "CTRL + F")) {
|
||||
this->getWindowOpenState() = true;
|
||||
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.menu.file.search"_lang); });
|
||||
ImGui::OpenPopupInWindow(View::toWindowName("hex.view.hexeditor.name").c_str(), "hex.view.hexeditor.menu.file.search"_lang);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.goto"_lang, "CTRL + G")) {
|
||||
this->getWindowOpenState() = true;
|
||||
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.menu.file.goto"_lang); });
|
||||
ImGui::OpenPopupInWindow(View::toWindowName("hex.view.hexeditor.name").c_str(), "hex.view.hexeditor.menu.file.goto"_lang);
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
@@ -633,13 +632,15 @@ namespace hex {
|
||||
if (ImHexApi::Provider::isValid())
|
||||
ImHexApi::Provider::get()->redo();
|
||||
} else if (ctrl && keys['F']) {
|
||||
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.menu.file.search"_lang); });
|
||||
ImGui::OpenPopupInWindow(View::toWindowName("hex.view.hexeditor.name").c_str(), "hex.view.hexeditor.menu.file.search"_lang);
|
||||
return true;
|
||||
} else if (ctrl && keys['G']) {
|
||||
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.menu.file.goto"_lang); });
|
||||
ImGui::OpenPopupInWindow(View::toWindowName("hex.view.hexeditor.name").c_str(), "hex.view.hexeditor.menu.file.goto"_lang);
|
||||
return true;
|
||||
} else if (ctrl && keys['O']) {
|
||||
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.open_file"_lang); });
|
||||
hex::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [](auto path) {
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
});
|
||||
return true;
|
||||
} else if (ctrl && keys['C']) {
|
||||
this->copyBytes();
|
||||
@@ -1042,7 +1043,7 @@ R"(
|
||||
foundCharacters = 0;
|
||||
|
||||
if (foundCharacters == string.size()) {
|
||||
results.emplace_back(offset + i - foundCharacters + 1, offset + i + 1);
|
||||
results.emplace_back(offset + i - foundCharacters + 1, offset + i);
|
||||
foundCharacters = 0;
|
||||
}
|
||||
}
|
||||
@@ -1080,7 +1081,7 @@ R"(
|
||||
foundCharacters = 0;
|
||||
|
||||
if (foundCharacters == hex.size()) {
|
||||
results.emplace_back(offset + i - foundCharacters + 1, offset + i + 1);
|
||||
results.emplace_back(offset + i - foundCharacters + 1, offset + i);
|
||||
foundCharacters = 0;
|
||||
}
|
||||
}
|
||||
@@ -1136,8 +1137,9 @@ R"(
|
||||
}
|
||||
};
|
||||
|
||||
if (ImGui::BeginPopupContextVoid("hex.view.hexeditor.menu.file.search"_lang)) {
|
||||
ImGui::TextUnformatted("hex.view.hexeditor.menu.file.search"_lang);
|
||||
|
||||
ImGui::SetNextWindowPos(ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin() - ImGui::GetStyle().WindowPadding);
|
||||
if (ImGui::BeginPopup("hex.view.hexeditor.menu.file.search"_lang)) {
|
||||
if (ImGui::BeginTabBar("searchTabs")) {
|
||||
std::vector<char> *currBuffer = nullptr;
|
||||
if (ImGui::BeginTabItem("hex.view.hexeditor.search.string"_lang)) {
|
||||
@@ -1179,7 +1181,6 @@ R"(
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
@@ -1189,8 +1190,8 @@ R"(
|
||||
auto baseAddress = provider->getBaseAddress();
|
||||
auto dataSize = provider->getActualSize();
|
||||
|
||||
ImGui::SetNextWindowPos(ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin() - ImGui::GetStyle().WindowPadding);
|
||||
if (ImGui::BeginPopup("hex.view.hexeditor.menu.file.goto"_lang)) {
|
||||
ImGui::TextUnformatted("hex.view.hexeditor.menu.file.goto"_lang);
|
||||
if (ImGui::BeginTabBar("gotoTabs")) {
|
||||
u64 newOffset = 0;
|
||||
if (ImGui::BeginTabItem("hex.view.hexeditor.goto.offset.absolute"_lang)) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
namespace hex {
|
||||
|
||||
using namespace hex::literals;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static const TextEditor::LanguageDefinition& PatternLanguage() {
|
||||
static bool initialized = false;
|
||||
@@ -32,7 +33,7 @@ namespace hex {
|
||||
"u8", "u16", "u32", "u64", "u128",
|
||||
"s8", "s16", "s32", "s64", "s128",
|
||||
"float", "double", "char", "char16",
|
||||
"bool", "padding", "str"
|
||||
"bool", "padding", "str", "auto"
|
||||
};
|
||||
|
||||
for (const auto name : builtInTypes) {
|
||||
@@ -96,18 +97,19 @@ namespace hex {
|
||||
this->parsePattern(this->m_textEditor.GetText().data());
|
||||
});
|
||||
|
||||
EventManager::subscribe<RequestAppendPatternLanguageCode>(this, [this](std::string code) {
|
||||
this->m_textEditor.InsertText("\n");
|
||||
EventManager::subscribe<RequestSetPatternLanguageCode>(this, [this](std::string code) {
|
||||
this->m_textEditor.SelectAll();
|
||||
this->m_textEditor.Delete();
|
||||
this->m_textEditor.InsertText(code);
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventFileLoaded>(this, [this](const std::string &path) {
|
||||
if (this->m_textEditor.GetText().find_first_not_of(" \f\n\r\t\v") != std::string::npos)
|
||||
if (!ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", 1))
|
||||
return;
|
||||
|
||||
pl::Preprocessor preprocessor;
|
||||
|
||||
if (ImHexApi::Provider::isValid())
|
||||
if (!ImHexApi::Provider::isValid())
|
||||
return;
|
||||
|
||||
std::string mimeType = magic::getMIMEType(ImHexApi::Provider::get());
|
||||
@@ -127,6 +129,7 @@ namespace hex {
|
||||
std::error_code errorCode;
|
||||
for (const auto &dir : hex::getPath(ImHexPath::Patterns)) {
|
||||
for (auto &entry : std::filesystem::directory_iterator(dir, errorCode)) {
|
||||
foundCorrectType = false;
|
||||
if (!entry.is_regular_file())
|
||||
continue;
|
||||
|
||||
@@ -137,14 +140,15 @@ namespace hex {
|
||||
preprocessor.preprocess(file.readString());
|
||||
|
||||
if (foundCorrectType)
|
||||
this->m_possiblePatternFiles.push_back(entry.path().string());
|
||||
this->m_possiblePatternFiles.push_back(entry.path());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!this->m_possiblePatternFiles.empty()) {
|
||||
this->m_selectedPatternFile = 0;
|
||||
View::doLater([] { ImGui::OpenPopup("hex.view.pattern.accept_pattern"_lang); });
|
||||
EventManager::post<RequestOpenPopup>("hex.view.pattern.accept_pattern"_lang);
|
||||
this->m_acceptPatternWindowOpen = true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -174,7 +178,7 @@ namespace hex {
|
||||
|
||||
EventManager::unsubscribe<EventProjectFileStore>(this);
|
||||
EventManager::unsubscribe<EventProjectFileLoad>(this);
|
||||
EventManager::unsubscribe<RequestAppendPatternLanguageCode>(this);
|
||||
EventManager::unsubscribe<RequestSetPatternLanguageCode>(this);
|
||||
EventManager::unsubscribe<EventFileLoaded>(this);
|
||||
EventManager::unsubscribe<RequestChangeTheme>(this);
|
||||
}
|
||||
@@ -182,9 +186,19 @@ namespace hex {
|
||||
void ViewPatternEditor::drawMenu() {
|
||||
if (ImGui::BeginMenu("hex.menu.file"_lang)) {
|
||||
if (ImGui::MenuItem("hex.view.pattern.menu.file.load_pattern"_lang)) {
|
||||
hex::openFileBrowser("hex.view.pattern.open_pattern"_lang, DialogMode::Open, { { "Pattern File", "hexpat" } }, [this](auto path) {
|
||||
this->loadPatternFile(path);
|
||||
});
|
||||
|
||||
this->m_selectedPatternFile = 0;
|
||||
this->m_possiblePatternFiles.clear();
|
||||
|
||||
for (auto &imhexPath : hex::getPath(ImHexPath::Patterns)) {
|
||||
for (auto &entry: fs::recursive_directory_iterator(imhexPath)) {
|
||||
if (entry.is_regular_file() && entry.path().extension() == ".hexpat") {
|
||||
this->m_possiblePatternFiles.push_back(entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
View::doLater([]{ ImGui::OpenPopup("hex.view.pattern.menu.file.load_pattern"_lang); });
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
@@ -252,14 +266,14 @@ namespace hex {
|
||||
}
|
||||
|
||||
if (this->m_textEditor.IsTextChanged()) {
|
||||
ProjectFile::markDirty();
|
||||
|
||||
if (this->m_runAutomatically)
|
||||
this->m_hasUnevaluatedChanges = true;
|
||||
}
|
||||
|
||||
if (this->m_hasUnevaluatedChanges && !this->m_evaluatorRunning) {
|
||||
this->m_hasUnevaluatedChanges = false;
|
||||
ProjectFile::markDirty();
|
||||
|
||||
this->parsePattern(this->m_textEditor.GetText().data());
|
||||
}
|
||||
}
|
||||
@@ -270,7 +284,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ViewPatternEditor::drawAlwaysVisible() {
|
||||
if (ImGui::BeginPopupModal("hex.view.pattern.accept_pattern"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
if (ImGui::BeginPopupModal("hex.view.pattern.accept_pattern"_lang, &this->m_acceptPatternWindowOpen, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextWrapped("%s", static_cast<const char *>("hex.view.pattern.accept_pattern.desc"_lang));
|
||||
|
||||
std::vector<std::string> entries;
|
||||
@@ -280,19 +294,23 @@ namespace hex {
|
||||
entries[i] = std::filesystem::path(this->m_possiblePatternFiles[i]).filename().string();
|
||||
}
|
||||
|
||||
ImGui::ListBox("hex.view.pattern.accept_pattern.pattern_language"_lang, &this->m_selectedPatternFile, [](void *data, int id, const char** outText) -> bool {
|
||||
auto &entries = *static_cast<std::vector<std::string>*>(data);
|
||||
if (ImGui::BeginListBox("##patterns_accept", ImVec2(-FLT_MIN, 0))) {
|
||||
|
||||
*outText = entries[id].c_str();
|
||||
u32 index = 0;
|
||||
for (auto &path : this->m_possiblePatternFiles) {
|
||||
if (ImGui::Selectable(path.filename().string().c_str(), index == this->m_selectedPatternFile))
|
||||
this->m_selectedPatternFile = index;
|
||||
index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}, &entries, entries.size(), 4);
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::Text("%s", static_cast<const char *>("hex.view.pattern.accept_pattern.question"_lang));
|
||||
|
||||
confirmButtons("hex.common.yes"_lang, "hex.common.no"_lang, [this]{
|
||||
this->loadPatternFile(this->m_possiblePatternFiles[this->m_selectedPatternFile]);
|
||||
this->loadPatternFile(this->m_possiblePatternFiles[this->m_selectedPatternFile].string());
|
||||
ImGui::CloseCurrentPopup();
|
||||
}, []{
|
||||
ImGui::CloseCurrentPopup();
|
||||
@@ -303,6 +321,37 @@ namespace hex {
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupModal("hex.view.pattern.menu.file.load_pattern"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
|
||||
if (ImGui::BeginListBox("##patterns", ImVec2(-FLT_MIN, 0))) {
|
||||
|
||||
u32 index = 0;
|
||||
for (auto &path : this->m_possiblePatternFiles) {
|
||||
if (ImGui::Selectable(path.filename().string().c_str(), index == this->m_selectedPatternFile))
|
||||
this->m_selectedPatternFile = index;
|
||||
index++;
|
||||
}
|
||||
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
|
||||
if (ImGui::Button("hex.common.open"_lang)) {
|
||||
this->loadPatternFile(this->m_possiblePatternFiles[this->m_selectedPatternFile].string());
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("hex.common.browse"_lang)) {
|
||||
hex::openFileBrowser("hex.view.pattern.open_pattern"_lang, DialogMode::Open, { { "Pattern File", "hexpat" } }, [this](auto path) {
|
||||
this->loadPatternFile(path);
|
||||
ImGui::CloseCurrentPopup();
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -341,9 +390,9 @@ namespace hex {
|
||||
void ViewPatternEditor::parsePattern(char *buffer) {
|
||||
this->m_evaluatorRunning = true;
|
||||
|
||||
this->clearPatternData();
|
||||
this->m_textEditor.SetErrorMarkers({ });
|
||||
this->m_console.clear();
|
||||
this->clearPatternData();
|
||||
EventManager::post<EventPatternChanged>();
|
||||
|
||||
std::thread([this, buffer = std::string(buffer)] {
|
||||
@@ -358,9 +407,9 @@ namespace hex {
|
||||
|
||||
if (result.has_value()) {
|
||||
SharedData::patternData = std::move(result.value());
|
||||
View::doLater([]{
|
||||
//View::doLater([]{
|
||||
EventManager::post<EventPatternChanged>();
|
||||
});
|
||||
//});
|
||||
}
|
||||
|
||||
this->m_evaluatorRunning = false;
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <microtar.h>
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -34,7 +36,7 @@ namespace hex {
|
||||
this->refresh();
|
||||
}
|
||||
|
||||
auto drawTab = [this](auto title, ImHexPath pathType, auto &content, std::function<void()> downloadDoneCallback) {
|
||||
auto drawTab = [this](auto title, ImHexPath pathType, auto &content, std::function<void(const StoreEntry&)> downloadDoneCallback) {
|
||||
if (ImGui::BeginTabItem(title)) {
|
||||
if (ImGui::BeginTable("##pattern_language", 3, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_RowBg)) {
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
@@ -66,7 +68,34 @@ namespace hex {
|
||||
if (response.code == 200) {
|
||||
entry.installed = true;
|
||||
entry.hasUpdate = false;
|
||||
downloadDoneCallback();
|
||||
|
||||
if (entry.isFolder) {
|
||||
mtar_t ctx;
|
||||
mtar_open(&ctx, this->m_downloadPath.string().c_str(), "r");
|
||||
|
||||
mtar_header_t header;
|
||||
auto extractBasePath = this->m_downloadPath.parent_path() / this->m_downloadPath.stem();
|
||||
while (mtar_read_header(&ctx, &header) != MTAR_ENULLRECORD) {
|
||||
auto filePath = extractBasePath / fs::path(header.name);
|
||||
fs::create_directories(filePath.parent_path());
|
||||
File outputFile(filePath.string(), File::Mode::Create);
|
||||
|
||||
std::vector<u8> buffer(0x10000);
|
||||
for (u64 offset = 0; offset < header.size; offset += buffer.size()) {
|
||||
auto readSize = std::min(buffer.size(), header.size - offset);
|
||||
mtar_read_data(&ctx, buffer.data(), readSize);
|
||||
|
||||
buffer.resize(readSize);
|
||||
outputFile.write(buffer);
|
||||
}
|
||||
mtar_next(&ctx);
|
||||
}
|
||||
|
||||
mtar_finalize(&ctx);
|
||||
mtar_close(&ctx);
|
||||
}
|
||||
|
||||
downloadDoneCallback(entry);
|
||||
} else
|
||||
log::error("Download failed!");
|
||||
|
||||
@@ -103,12 +132,17 @@ namespace hex {
|
||||
};
|
||||
|
||||
if (ImGui::BeginTabBar("storeTabs")) {
|
||||
drawTab("hex.view.store.tab.patterns"_lang, ImHexPath::Patterns, this->m_patterns, []{});
|
||||
drawTab("hex.view.store.tab.libraries"_lang, ImHexPath::PatternsInclude, this->m_includes, []{});
|
||||
drawTab("hex.view.store.tab.magics"_lang, ImHexPath::Magic, this->m_magics, []{
|
||||
auto extractTar = []{
|
||||
|
||||
};
|
||||
|
||||
drawTab("hex.view.store.tab.patterns"_lang, ImHexPath::Patterns, this->m_patterns, [](auto){});
|
||||
drawTab("hex.view.store.tab.libraries"_lang, ImHexPath::PatternsInclude, this->m_includes, [](auto){});
|
||||
drawTab("hex.view.store.tab.magics"_lang, ImHexPath::Magic, this->m_magics, [](auto){
|
||||
magic::compile();
|
||||
});
|
||||
drawTab("hex.view.store.tab.constants"_lang, ImHexPath::Constants, this->m_constants, []{});
|
||||
drawTab("hex.view.store.tab.constants"_lang, ImHexPath::Constants, this->m_constants, [](auto){});
|
||||
drawTab("hex.view.store.tab.yara"_lang, ImHexPath::Yara, this->m_yara, [](auto){});
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
@@ -119,6 +153,7 @@ namespace hex {
|
||||
this->m_includes.clear();
|
||||
this->m_magics.clear();
|
||||
this->m_constants.clear();
|
||||
this->m_yara.clear();
|
||||
|
||||
this->m_apiRequest = this->m_net.getString(ImHexApiURL + "/store"s);
|
||||
}
|
||||
@@ -135,10 +170,10 @@ namespace hex {
|
||||
for (auto &entry : storeJson[name]) {
|
||||
|
||||
// Check if entry is valid
|
||||
if (entry.contains("name") && entry.contains("desc") && entry.contains("file") && entry.contains("url") && entry.contains("hash")) {
|
||||
if (entry.contains("name") && entry.contains("desc") && entry.contains("file") && entry.contains("url") && entry.contains("hash") && entry.contains("folder")) {
|
||||
|
||||
// Parse entry
|
||||
StoreEntry storeEntry = { entry["name"], entry["desc"], entry["file"], entry["url"], entry["hash"], false, false, false };
|
||||
StoreEntry storeEntry = { entry["name"], entry["desc"], entry["file"], entry["url"], entry["hash"], entry["folder"],false, false, false };
|
||||
|
||||
// Check if file is installed already or has an update available
|
||||
for (const auto &folder : hex::getPath(pathType)) {
|
||||
@@ -170,6 +205,7 @@ namespace hex {
|
||||
parseStoreEntries(json, "includes", ImHexPath::PatternsInclude, this->m_includes);
|
||||
parseStoreEntries(json, "magic", ImHexPath::Magic, this->m_magics);
|
||||
parseStoreEntries(json, "constants", ImHexPath::Constants, this->m_constants);
|
||||
parseStoreEntries(json, "yara", ImHexPath::Yara, this->m_yara);
|
||||
|
||||
}
|
||||
this->m_apiRequest = { };
|
||||
@@ -208,11 +244,13 @@ namespace hex {
|
||||
|
||||
void ViewStore::download(ImHexPath pathType, const std::string &fileName, const std::string &url, bool update) {
|
||||
if (!update) {
|
||||
this->m_download = this->m_net.downloadFile(url, hex::getPath(pathType).front() / fs::path(fileName));
|
||||
this->m_downloadPath = hex::getPath(pathType).front() / fs::path(fileName);
|
||||
this->m_download = this->m_net.downloadFile(url, this->m_downloadPath);
|
||||
} else {
|
||||
for (const auto &path : hex::getPath(pathType)) {
|
||||
auto fullPath = path / fs::path(fileName);
|
||||
if (fs::exists(fullPath)) {
|
||||
this->m_downloadPath = fullPath;
|
||||
this->m_download = this->m_net.downloadFile(url, fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,19 @@
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <yara.h>
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
|
||||
#include <imgui_imhex_extensions.h>
|
||||
#include <hex/helpers/paths.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
ViewYara::ViewYara() : View("hex.view.yara.name") {
|
||||
yr_initialize();
|
||||
|
||||
@@ -39,10 +43,10 @@ namespace hex {
|
||||
if (ImGui::Button("hex.view.yara.reload"_lang)) this->reloadRules();
|
||||
} else {
|
||||
ImGui::Disabled([this]{
|
||||
if (ImGui::BeginCombo("hex.view.yara.header.rules"_lang, this->m_rules[this->m_selectedRule].c_str())) {
|
||||
if (ImGui::BeginCombo("hex.view.yara.header.rules"_lang, this->m_rules[this->m_selectedRule].first.c_str())) {
|
||||
for (u32 i = 0; i < this->m_rules.size(); i++) {
|
||||
const bool selected = (this->m_selectedRule == i);
|
||||
if (ImGui::Selectable(this->m_rules[i].c_str(), selected))
|
||||
if (ImGui::Selectable(this->m_rules[i].first.c_str(), selected))
|
||||
this->m_selectedRule = i;
|
||||
|
||||
if (selected)
|
||||
@@ -119,12 +123,15 @@ namespace hex {
|
||||
void ViewYara::reloadRules() {
|
||||
this->m_rules.clear();
|
||||
|
||||
if (!std::filesystem::exists("./yara"))
|
||||
return;
|
||||
for (auto path : hex::getPath(ImHexPath::Yara)) {
|
||||
if (!fs::exists(path))
|
||||
continue;
|
||||
|
||||
for (const auto &entry : std::filesystem::directory_iterator("yara")) {
|
||||
if (entry.is_regular_file())
|
||||
this->m_rules.push_back(entry.path().string());
|
||||
for (const auto &entry : fs::recursive_directory_iterator(path)) {
|
||||
if (entry.is_regular_file() && entry.path().extension() == ".yar") {
|
||||
this->m_rules.push_back({ fs::relative(entry.path(), fs::path(path)).string(), entry.path().string() });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,21 +144,45 @@ namespace hex {
|
||||
|
||||
YR_COMPILER *compiler = nullptr;
|
||||
yr_compiler_create(&compiler);
|
||||
ON_SCOPE_EXIT {
|
||||
yr_compiler_destroy(compiler);
|
||||
this->m_matching = false;
|
||||
};
|
||||
|
||||
File file(this->m_rules[this->m_selectedRule], File::Mode::Read);
|
||||
yr_compiler_set_include_callback(
|
||||
compiler,
|
||||
[](const char *includeName, const char *callingRuleFileName, const char *callingRuleNamespace, void *userData) -> const char * {
|
||||
auto currFilePath = static_cast<const char*>(userData);
|
||||
|
||||
File file((fs::path(currFilePath).parent_path() / includeName).string(), File::Mode::Read);
|
||||
if (!file.isValid())
|
||||
return nullptr;
|
||||
|
||||
auto size = file.getSize();
|
||||
char *buffer = new char[size + 1];
|
||||
file.readBuffer(reinterpret_cast<u8*>(buffer), size);
|
||||
buffer[size] = 0x00;
|
||||
|
||||
return buffer;
|
||||
},
|
||||
[](const char *ptr, void *userData) {
|
||||
delete[] ptr;
|
||||
},
|
||||
this->m_rules[this->m_selectedRule].second.data());
|
||||
|
||||
|
||||
File file(this->m_rules[this->m_selectedRule].second, File::Mode::Read);
|
||||
if (!file.isValid()) return;
|
||||
|
||||
if (yr_compiler_add_file(compiler, file.getHandle(), nullptr, nullptr) != 0) {
|
||||
this->m_errorMessage.resize(0xFFFF);
|
||||
yr_compiler_get_error_message(compiler, this->m_errorMessage.data(), this->m_errorMessage.size());
|
||||
this->m_matching = false;
|
||||
return;
|
||||
}
|
||||
|
||||
YR_RULES *rules;
|
||||
yr_compiler_get_rules(compiler, &rules);
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
ON_SCOPE_EXIT { yr_rules_destroy(rules); };
|
||||
|
||||
std::vector<YaraMatch> newMatches;
|
||||
|
||||
@@ -232,10 +263,6 @@ namespace hex {
|
||||
}, &newMatches, 0);
|
||||
|
||||
std::copy(newMatches.begin(), newMatches.end(), std::back_inserter(this->m_matches));
|
||||
|
||||
yr_compiler_destroy(compiler);
|
||||
|
||||
this->m_matching = false;
|
||||
}).detach();
|
||||
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@
|
||||
POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||||
|
||||
const POINT border{
|
||||
static_cast<LONG>((::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * SharedData::globalScale / 2.0F),
|
||||
static_cast<LONG>((::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * SharedData::globalScale / 2.0F)
|
||||
static_cast<LONG>((::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * SharedData::globalScale / 1.5F),
|
||||
static_cast<LONG>((::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * SharedData::globalScale / 1.5F)
|
||||
};
|
||||
|
||||
RECT window;
|
||||
@@ -120,6 +120,9 @@
|
||||
RegionTop * (cursor.y < (window.top + border.y)) |
|
||||
RegionBottom * (cursor.y >= (window.bottom - border.y));
|
||||
|
||||
if (result != 0 && (ImGui::IsItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
|
||||
break;
|
||||
|
||||
switch (result) {
|
||||
case RegionLeft:
|
||||
return HTLEFT;
|
||||
@@ -139,7 +142,7 @@
|
||||
return HTBOTTOMRIGHT;
|
||||
case RegionClient:
|
||||
default:
|
||||
if ((cursor.y < (window.top + titleBarHeight)) && !(ImGui::IsAnyItemHovered() || ImGui::IsAnyItemFocused()))
|
||||
if ((cursor.y < (window.top + titleBarHeight * 2)) && !(ImGui::IsAnyItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
|
||||
return HTCAPTION;
|
||||
else break;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
@@ -222,6 +223,10 @@ namespace hex {
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<RequestOpenPopup>(this, [this](auto name){
|
||||
this->m_popupsToOpen.push_back(name);
|
||||
});
|
||||
|
||||
for (const auto &path : hex::getPath(ImHexPath::Config)) {
|
||||
if (auto filePath = std::filesystem::path(path) / CrashBackupFileName; std::filesystem::exists(filePath)) {
|
||||
this->m_safetyBackupPath = filePath;
|
||||
@@ -263,6 +268,7 @@ namespace hex {
|
||||
EventManager::unsubscribe<RequestChangeWindowTitle>(this);
|
||||
EventManager::unsubscribe<EventAbnormalTermination>(this);
|
||||
EventManager::unsubscribe<RequestChangeTheme>(this);
|
||||
EventManager::unsubscribe<RequestOpenPopup>(this);
|
||||
|
||||
ImGui::UnloadImage(this->m_bannerTexture);
|
||||
ImGui::UnloadImage(this->m_logoTexture);
|
||||
@@ -434,7 +440,6 @@ namespace hex {
|
||||
ImGui::SetCursorPosX(width / 9);
|
||||
if (ImGui::Button("hex.safety_backup.restore"_lang, ImVec2(width / 3, 0))) {
|
||||
ProjectFile::load(this->m_safetyBackupPath.string());
|
||||
EventManager::post<EventProjectFileLoad>();
|
||||
ProjectFile::markDirty();
|
||||
|
||||
ProjectFile::clearProjectFilePath();
|
||||
@@ -452,6 +457,15 @@ namespace hex {
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
this->m_popupsToOpen.remove_if([](const auto &name) {
|
||||
if (ImGui::IsPopupOpen(name.c_str()))
|
||||
return true;
|
||||
else
|
||||
ImGui::OpenPopup(name.c_str());
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void Window::frame() {
|
||||
@@ -761,7 +775,36 @@ namespace hex {
|
||||
if (count != 1)
|
||||
return;
|
||||
|
||||
EventManager::post<RequestOpenFile>(paths[0]);
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
auto path = std::filesystem::path(paths[i]);
|
||||
|
||||
if (path.extension() == ".hexpat" || path.extension() == ".pat") {
|
||||
File file(path.string(), File::Mode::Read);
|
||||
|
||||
if (file.isValid())
|
||||
EventManager::post<RequestSetPatternLanguageCode>(file.readString());
|
||||
} else if (path.extension() == ".hexproj") {
|
||||
ProjectFile::load(path.string());
|
||||
} else if (path.extension() == ".yar") {
|
||||
for (auto &destPath : hex::getPath(ImHexPath::Yara)) {
|
||||
std::error_code error;
|
||||
if (std::filesystem::copy_file(path, destPath / path.filename(), std::filesystem::copy_options::overwrite_existing, error)) {
|
||||
View::showMessagePopup("hex.message.yara_rule_added"_lang);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (path.extension() == ".mgc") {
|
||||
for (auto &destPath : hex::getPath(ImHexPath::Magic)) {
|
||||
std::error_code error;
|
||||
if (std::filesystem::copy_file(path, destPath / path.filename(), std::filesystem::copy_options::overwrite_existing, error)) {
|
||||
View::showMessagePopup("hex.message.magic_db_added"_lang);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EventManager::post<RequestOpenFile>(path.string());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
glfwSetWindowCloseCallback(this->m_window, [](GLFWwindow *window) {
|
||||
|
||||
@@ -18,6 +18,7 @@ set(AVAILABLE_TESTS
|
||||
RValues
|
||||
Namespaces
|
||||
ExtraSemicolon
|
||||
Pointers
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -7,13 +7,14 @@ namespace hex::test {
|
||||
class TestPatternEnums : public TestPattern {
|
||||
public:
|
||||
TestPatternEnums() : TestPattern("Enums"){
|
||||
auto testEnum = create<PatternDataEnum>("TestEnum", "testEnum", 0x120, sizeof(u32));
|
||||
auto testEnum = create<PatternDataEnum>("TestEnum", "testEnum", 0x08, sizeof(u32));
|
||||
testEnum->setEnumValues({
|
||||
{ u128(0x0000), "A" },
|
||||
{ s128(0x1234), "B" },
|
||||
{ u128(0x1235), "C" },
|
||||
{ u128(0x1236), "D" },
|
||||
{ s128(0x0C), "B" },
|
||||
{ u128(0x0D), "C" },
|
||||
{ u128(0x0E), "D" },
|
||||
});
|
||||
testEnum->setEndian(std::endian::big);
|
||||
|
||||
addPattern(testEnum);
|
||||
}
|
||||
@@ -24,12 +25,14 @@ namespace hex::test {
|
||||
return R"(
|
||||
enum TestEnum : u32 {
|
||||
A,
|
||||
B = 0x1234,
|
||||
B = 0x0C,
|
||||
C,
|
||||
D
|
||||
};
|
||||
|
||||
TestEnum testEnum @ 0x120;
|
||||
be TestEnum testEnum @ 0x08;
|
||||
|
||||
std::assert(testEnum == TestEnum::C, "Invalid enum value");
|
||||
)";
|
||||
}
|
||||
|
||||
|
||||
30
tests/include/test_patterns/test_pattern_pointers.hpp
Normal file
30
tests/include/test_patterns/test_pattern_pointers.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternPointers : public TestPattern {
|
||||
public:
|
||||
TestPatternPointers() : TestPattern("Pointers") {
|
||||
// placementPointer
|
||||
{
|
||||
auto placementPointer = create<PatternDataPointer>("", "placementPointer", 0x0C, sizeof(u8));
|
||||
auto pointedTo = create<PatternDataUnsigned>("u32", "", 0x49, sizeof(u32));
|
||||
placementPointer->setPointedAtPattern(pointedTo);
|
||||
addPattern(placementPointer);
|
||||
}
|
||||
|
||||
}
|
||||
~TestPatternPointers() override = default;
|
||||
|
||||
[[nodiscard]]
|
||||
std::string getSourceCode() const override {
|
||||
return R"(
|
||||
u32 *placementPointer : u8 @ 0x0C;
|
||||
)";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -97,7 +97,7 @@ int test(int argc, char **argv) {
|
||||
auto &controlPattern = *currTest->getPatterns().at(i);
|
||||
|
||||
if (evaluatedPattern != controlPattern) {
|
||||
hex::log::fatal("Pattern with name {}:{} didn't match template", patterns->at(i)->getTypeName(), patterns->at(i)->getVariableName());
|
||||
hex::log::fatal("Pattern with name {}:{} didn't match template", evaluatedPattern.getTypeName(), evaluatedPattern.getVariableName());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "test_patterns/test_pattern_rvalues.hpp"
|
||||
#include "test_patterns/test_pattern_namespaces.hpp"
|
||||
#include "test_patterns/test_pattern_extra_semicolon.hpp"
|
||||
#include "test_patterns/test_pattern_pointers.hpp"
|
||||
|
||||
std::array Tests = {
|
||||
TEST(Placement),
|
||||
@@ -27,5 +28,6 @@ std::array Tests = {
|
||||
TEST(Math),
|
||||
TEST(RValues),
|
||||
TEST(Namespaces),
|
||||
TEST(ExtraSemicolon)
|
||||
TEST(ExtraSemicolon),
|
||||
TEST(Pointers)
|
||||
};
|
||||
Reference in New Issue
Block a user