diff --git a/README.md b/README.md index 95157a0..427b749 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # ddhx, Interactive Hexadecimal File Viewer -**NOTE:** Please note that ddhx is an inactive project. - ![Screenshot of ddhx](https://dd86k.github.io/imgs/ddhx3.png) ddhx is a replacement for [0xdd](https://github.com/dd86k/0xdd) as a native tool. @@ -11,9 +9,9 @@ Searching for an ASCII string? Press the return key, or escape, type in `ss IEND` and ddhx will search for "IEND"! Notes: -- Some commands take in sub-command parameters, e.g. `search u8 0xdd`. +- Some commands take command parameters, e.g. `search u8 0xdd`. - Some commands have _aliases_, e.g. `sb 0xdd` is the same as `search u8 0xdd`. -- Some commands have a key binded as a command, e.g. pressing `r` while not in command-mode executes the equivelent of `refresh`. +- Some commands have a shortcut, e.g. pressing `r` while outside of command mode executes `refresh`. Here is a brief list of commands: diff --git a/dub.sdl b/dub.sdl index 32504ed..f9b3051 100644 --- a/dub.sdl +++ b/dub.sdl @@ -2,4 +2,8 @@ description "Hexadecimal file viewer" authors "dd86k" copyright "Copyright © 2017-2019 dd86k" -license "MIT" \ No newline at end of file +license "MIT" + +buildType "verbose" { + dflags "-vgc" "-vtls" +} \ No newline at end of file diff --git a/src/Menu.d b/src/Menu.d index 6c6e6d6..6ff226e 100644 --- a/src/Menu.d +++ b/src/Menu.d @@ -133,15 +133,16 @@ } HandleOffset(argv[1]); hxoffsetbar; - hxupdate_r; + hxrender_r; break; case "refresh": hxrefresh_a; break; case "quit": hxexit; break; case "about": - msgalt("Written by dd86k. Copyright (c) dd86k 2017-2019"); + enum C = "Written by dd86k. " ~ COPYRIGHT; + msgalt(C); break; case "version": - enum V = "Using ddhx " ~ APP_VERSION; + enum V = "ddhx " ~ APP_VERSION ~ ", " ~ __TIMESTAMP__; msgalt(V); break; // diff --git a/src/Searcher.d b/src/Searcher.d index c1dbb83..dfc7654 100644 --- a/src/Searcher.d +++ b/src/Searcher.d @@ -26,40 +26,35 @@ * Search an UTF-16 string * Params: * s = string - * invert = Invert endianness */ -void search_utf16(const char[] s, bool invert = false) { - //TODO: See if we can use proper UTF-16 conversion +void search_utf16(const char[] s) { wstring ws; transcode(s, ws); + ubyte[1024] buf = void; + wchar* p = cast(wchar*)buf; size_t l; - wchar* wp = cast(wchar*)ws; - while (*wp != 0xFFFF) { ++wp; ++l; } - l *= 2; - ubyte[] buf = new ubyte[l]; - memcpy(cast(byte*)buf, cast(byte*)ws, l); - //TODO: invert - search_arr(buf, "wstring"); + foreach (const wchar c; ws) { + p[l++] = c; + } + search_arr(buf[0..l], "wstring"); } /** * Search an UTF-32 string * Params: * s = string - * invert = Invert endianness */ -void search_utf32(const char[] s, bool invert = false) { +void search_utf32(const char[] s) { //TODO: See if we can use proper UTF-32 conversion dstring ds; transcode(s, ds); + ubyte[1024] buf = void; + wchar* p = cast(wchar*)buf; size_t l; - wchar* dp = cast(wchar*)ds; - while (*dp != 0xFFFF) { ++dp; ++l; } - l *= 4; - ubyte[] buf = new ubyte[l]; - memcpy(cast(byte*)buf, cast(byte*)ds, l); - //TODO: invert - search_arr(buf, "dstring"); + foreach (const wchar c; ds) { + p[l++] = c; + } + search_arr(buf[0..l], "dstring"); } /** @@ -81,13 +76,14 @@ */ void search_u16(string s, bool invert = false) { long l = void; - if (unformat(s, l)) { - const ushort u16 = invert ? bswap16(cast(ushort)l) : cast(ushort)l; - ubyte[2] la = void; - *(cast(ushort*)la) = u16; - search_arr(la, "u16"); - } else + if (unformat(s, l) == false) { msgalt("Could not parse number"); + return; + } + const ushort u16 = invert ? bswap16(cast(ushort)l) : cast(ushort)l; + ubyte[2] la = void; + *(cast(ushort*)la) = u16; + search_arr(la, "u16"); } /** @@ -98,13 +94,14 @@ */ void search_u32(string s, bool invert = false) { long l = void; - if (unformat(s, l)) { - const uint u32 = invert ? bswap32(cast(uint)l) : cast(uint)l; - ubyte[4] la = void; - *(cast(uint*)la) = u32; - search_arr(la, "u32"); - } else + if (unformat(s, l) == false) { msgalt("Could not parse number"); + return; + } + const uint u32 = invert ? bswap32(cast(uint)l) : cast(uint)l; + ubyte[4] la = void; + *(cast(uint*)la) = u32; + search_arr(la, "u32"); } /** @@ -130,7 +127,7 @@ const size_t datal = data.length; long pos = fpos + 1; // To not affect file position itself - outer: foreach (const ubyte[] buf; (cast(ubyte[])MMFile[]).chunks(CHUNK_SIZE)) { + outer: foreach (const ubyte[] buf; (cast(ubyte[])CFile[]).chunks(CHUNK_SIZE)) { const size_t bufl = buf.length; inner: for (size_t i; i < bufl; ++i) { if (buf[i] != firstbyte) break inner; diff --git a/src/ddhx.d b/src/ddhx.d index 1f8e4b5..b49a63e 100644 --- a/src/ddhx.d +++ b/src/ddhx.d @@ -3,16 +3,18 @@ */ module ddhx; -import std.stdio : write, writef, writeln; +import std.stdio : write, writeln, writef, writefln; import std.mmfile; -import core.stdc.stdio : printf, puts; -import core.stdc.stdlib; +import core.stdc.stdio : printf; import core.stdc.string : memset; import menu, ddcon; import utils : formatsize, unformat; //TODO: retain window dimensions until a new size event or something +/// Copyright string +enum COPYRIGHT = "Copyright (c) dd86k 2017-2019"; + /// App version enum APP_VERSION = "0.2.0"; @@ -29,13 +31,6 @@ /// Default character for non-displayable characters enum DEFAULT_CHAR = '.'; -/// Preferred table over computing the same values again$(BR) -/// Hint: Fast -private __gshared const char[] hexTable = [ - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', -]; - /// For header private __gshared const char[] offsetTable = [ 'h', 'd', 'o' @@ -60,9 +55,9 @@ // Internal // -__gshared MmFile MMFile = void; /// Main mmfile +__gshared MmFile CFile = void; /// Current file __gshared ubyte* mmbuf = void; /// mmfile buffer address -__gshared uint screenl = void; /// screen size +__gshared uint screenl = void; /// screen size in bytes, 1 dimensional buffer __gshared string fname = void; /// filename __gshared long fpos = void; /// Current file position @@ -79,7 +74,7 @@ hxprep; screenclear; hxoffsetbar; - hxupdate_r; + hxrender_r; hxinfobar_r; KeyInfo k = void; @@ -213,7 +208,7 @@ hxprep; screenclear; hxoffsetbar; - hxupdate_r; + hxrender_r; hxinfobar_r; } @@ -267,7 +262,7 @@ void hxgoto(long pos) { if (screenl < fsize) { fpos = pos; - hxupdate; + hxrender; hxinfobar_r; } else msgalt("Navigation disabled, buffer too small."); @@ -281,7 +276,7 @@ extern (C) void hxgoto_c(long pos) { if (pos + screenl > fsize) - hxgoto(fsize - screenl);//Buffer.length); + hxgoto(fsize - screenl); else hxgoto(pos); } @@ -292,8 +287,8 @@ * Params: str = String as a number */ void gotostr(string str) { - byte rel; // Lazy code - if (str[0] == '+') { + byte rel = void; // Lazy code + if (str[0] == '+') { // relative position rel = 1; str = str[1..$]; } else if (str[0] == '-') { @@ -326,40 +321,43 @@ /// Update display from buffer extern (C) -void hxupdate() { +void hxrender() { screenpos(0, 1); - hxupdate_r; + hxrender_r; } /// Update display from buffer without setting cursor extern (C) -void hxupdate_r() { +void hxrender_r() { import core.stdc.string : memset; - char [1024]a = void; - char [1024]d = void; + + __gshared char[] hexTable = [ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + ]; + + char[1024] a = void, d = void; size_t brow = BytesPerRow; /// bytes per row int minw = cast(int)brow * 3; - a[brow] = '\0'; - d[minw] = '\0'; + a[brow] = d[minw] = '\0'; - long p = fpos; - const long blen = p + screenl; + size_t p = cast(size_t)fpos, wlen = p + screenl; /// window length - //TODO: if >fsize, then slice differently - ubyte[] fbuf = cast(ubyte[])MMFile[p..blen]; + //TODO: if wlen>fsize, then slice differently + // range, does not allocate + const ubyte[] fbuf = cast(ubyte[])CFile[p..wlen]; - char [32]bytef = cast(char[32])"%08X %s %s\n"; + char[12] bytef = cast(char[12])"%08X %s %s\n"; bytef[3] = formatTable[CurrentOffsetType]; - for (size_t bi; p < blen; p += brow) { + for (size_t bi; p < wlen; p += brow) { const bool over = p + brow > fsize; if (over) { brow = cast(uint)(fsize - p); - memset(cast(char*)a, ' ', BytesPerRow); - memset(cast(char*)d, ' ', minw); + minw = brow * 3; } for (size_t di, ai; ai < brow; ++ai) { @@ -367,10 +365,10 @@ d[di++] = ' '; d[di++] = hexTable[b >> 4]; d[di++] = hexTable[b & 15]; - a[ai] = fchar(b); + a[ai] = b > 0x7E || b < 0x20 ? DEFAULT_CHAR : b; } - printf(cast(char*)bytef, p, cast(char*)d, cast(char*)a); + writef(bytef, p, d[0..minw], a[0..brow]); if (over) return; } @@ -420,15 +418,4 @@ import core.stdc.stdlib : exit; screenclear; exit(0); -} - -/** - * Converts an unsigned byte to an ASCII character. If the byte is outside of - * the ASCII range, $(D DEFAULT_CHAR) will be returned. - * Params: c = Unsigned byte - * Returns: ASCII character - */ -extern (C) -char fchar(ubyte c) pure @safe @nogc nothrow { //TODO: EIBEC? - return c > 0x7E || c < 0x20 ? DEFAULT_CHAR : c; } \ No newline at end of file diff --git a/src/main.d b/src/main.d index 3d6695b..aa82a75 100644 --- a/src/main.d +++ b/src/main.d @@ -40,7 +40,7 @@ writefln( "ddhx " ~ APP_VERSION ~ " (" ~ __TIMESTAMP__ ~ ")\n" ~ "Compiler: " ~ __VENDOR__ ~ " v%d\n" ~ - "MIT License: Copyright (c) dd86k 2017-2019\n" ~ + "MIT License: "~COPYRIGHT~"\n" ~ "Project page: ", __VERSION__ ); @@ -78,9 +78,9 @@ return 3; } - MMFile = new MmFile((fname = file), MmFile.Mode.read, 0, mmbuf); + CFile = new MmFile((fname = file), MmFile.Mode.read, 0, mmbuf); - if ((fsize = MMFile.length) <= 0) { + if ((fsize = CFile.length) <= 0) { stderr.writeln("Empty file, aborting"); return 4; }