Compare commits

..

41 Commits

Author SHA1 Message Date
WerWolv
066161f397 build: Bump version to 1.10.1 2021-09-30 12:52:12 +02:00
WerWolv
d3e3de3fa2 ux: Improved dropped file loading; Added magic db loading 2021-09-30 12:29:03 +02:00
WerWolv
194bc3e5be settings: Add option for auto-loading patterns 2021-09-30 12:00:11 +02:00
WerWolv
a9e3db0464 patterns: Fixed inlined variable drawing 2021-09-29 20:51:57 +02:00
WerWolv
334ba3ede2 hex-editor: Fixed open file shortcut, improved find/goto popup position 2021-09-28 12:34:55 +02:00
WerWolv
7978964995 ui: Centered "No bookmarks" text 2021-09-27 23:19:41 +02:00
WerWolv
d5ca4c4f28 patterns: Fixed pointer name displaying 2021-09-27 20:16:23 +02:00
WerWolv
08c2e1cd4e patterns: Added [[transform]] and [[pointer_base]] attributes 2021-09-27 18:32:48 +02:00
WerWolv
2f6e91cd9e fix: Open Popup crash 2021-09-27 15:04:30 +02:00
WerWolv
888976873a patterns: Added [[inline]] attribute 2021-09-27 13:31:10 +02:00
WerWolv
5db608c3fc ui: Fixed automatic pattern loading, added better pattern browse popup 2021-09-26 21:18:25 +02:00
WerWolv
e46807c600 ux: Open dropped pattern files in pattern editor 2021-09-26 21:17:46 +02:00
WerWolv
7799bbb57a ui: Improved borderless window resizing and moving 2021-09-26 21:16:49 +02:00
WerWolv
7da8a5b1d8 patterns: Unified expression body parsing 2021-09-26 18:27:18 +02:00
WerWolv
ae9f4fa876 patterns: Increased highlighting performance 2021-09-26 02:23:27 +02:00
WerWolv
e3dd5900e2 patterns: Added parse_int and parse_float functions 2021-09-26 02:23:10 +02:00
WerWolv
aab865fe25 patterns: Fix member access inside if body 2021-09-26 02:22:50 +02:00
WerWolv
62656f4c51 tests: Added pointer test 2021-09-25 23:31:37 +02:00
WerWolv
b323d711cf patterns: Respect endianess when accessing rvalues 2021-09-25 22:46:16 +02:00
WerWolv
9b4cf917d9 patterns: Fixed recursive types 2021-09-25 22:03:55 +02:00
WerWolv
ba97573f93 patterns: Fixed pointers not working correctly 2021-09-25 18:45:23 +02:00
WerWolv
9dc62e1469 patterns: Added std::http::get 2021-09-25 16:24:08 +02:00
WerWolv
55c0cb66e3 patterns: Ignore comments inside strings 2021-09-25 16:23:51 +02:00
WerWolv
a8526585cb patterns: Fixed string access 2021-09-25 14:52:34 +02:00
WerWolv
3850349eae patterns: Fixed enum entry scope resolution 2021-09-25 14:52:17 +02:00
WerWolv
f5bd0b7971 patterns: Moved std::str to std::string 2021-09-25 00:04:54 +02:00
WerWolv
42d9753bdb patterns: Fixed std::str::substr 2021-09-25 00:04:40 +02:00
WerWolv
17d5a5309a patterns: Fixed setting variables in functions 2021-09-25 00:03:32 +02:00
WerWolv
71be77c54b patterns: Fix boolean operations and cast syntax 2021-09-24 12:15:50 +02:00
WerWolv
93c1fbd65e patterns: Fixed function parameters being set in the wrong order 2021-09-24 11:34:06 +02:00
WerWolv
c8114347dc patterns: Fixed project only being marked dirty when evaluating 2021-09-24 01:55:30 +02:00
WerWolv
3c2c2b003f patterns: Fixed unary expressions in parenthesis 2021-09-24 01:55:00 +02:00
WerWolv
2edd6cd6c4 patterns: Added inheritance for structs 2021-09-24 00:47:34 +02:00
WerWolv
6713f65040 patterns: Added auto type 2021-09-23 23:43:16 +02:00
WerWolv
82ee4ad4ca yara: Fixed major memory leak and added include support 2021-09-23 22:57:19 +02:00
WerWolv
d9134f7fe1 store: Added support for downloading tar'd folders 2021-09-23 22:56:49 +02:00
KokaKiwi
ee26839292 build: Fix system libraries usage (#308)
Signed-off-by: KokaKiwi <kokakiwi+git@kokakiwi.net>
2021-09-23 22:01:38 +02:00
WerWolv
cd33376c07 ui: Added custom font size setting 2021-09-22 23:42:52 +02:00
WerWolv
e57481b87c tools: Added file shredder, splitter and combiner 2021-09-22 17:56:06 +02:00
WerWolv
5601aab043 fix: Close file option crashing 2021-09-22 12:58:49 +02:00
WerWolv
1b7a1852bc fix: Update prompt displaying even on current version 2021-09-22 12:57:40 +02:00
57 changed files with 2108 additions and 470 deletions

View File

@@ -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()

View File

@@ -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];

View File

@@ -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
View 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
View 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
View 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
View 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
View 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);
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;
};
}

View File

@@ -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));

View File

@@ -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;
});
}
}

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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", "\" Floppy disk (1200KiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "\" 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" },

View File

@@ -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", "\" Floppy disk (1200KiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "\" 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" },

View File

@@ -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" },

View File

@@ -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", "跟随系统" },

View File

@@ -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})

View File

@@ -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&);

View File

@@ -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;
};
}

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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();
}
}

View File

@@ -91,6 +91,7 @@ namespace hex::pl {
Float = 0x42,
Double = 0x82,
String = 0x15,
Auto = 0x16,
CustomType = 0x00,
Padding = 0x1F,

View File

@@ -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;

View File

@@ -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());
}
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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();

View File

@@ -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;

View File

@@ -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 };
}

View File

@@ -165,7 +165,7 @@ namespace hex {
code += "};\n";
EventManager::post<RequestAppendPatternLanguageCode>(code);
EventManager::post<RequestSetPatternLanguageCode>(code);
Py_RETURN_NONE;
}

View File

@@ -85,6 +85,8 @@ namespace hex {
ProjectFile::s_hasUnsavedChanged = false;
ProjectFile::s_currProjectFilePath = filePath;
EventManager::post<EventProjectFileLoad>();
return true;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)) {

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -18,6 +18,7 @@ set(AVAILABLE_TESTS
RValues
Namespaces
ExtraSemicolon
Pointers
)

View File

@@ -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");
)";
}

View 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;
)";
}
};
}

View File

@@ -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;
}
}

View File

@@ -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)
};