ultimatepp/uppsrc/HexView/HexView.cpp
2024-06-07 16:58:31 +02:00

486 lines
9.6 KiB
C++

#include "HexView.h"
namespace Upp {
inline int FormatHexDigit(int c) {
return c < 10 ? c + '0' : c - 10 + 'a';
}
void FormatHex(char *buffer, int64 number, int n) {
buffer[n] = '\0';
while(n) {
buffer[--n] = FormatHexDigit((byte)number & 0x0f);
number >>= 4;
}
}
void HexViewInfo::PrintValue(Draw& w, int x, int y, int bytes, bool be)
{
dword d = 0;
Size fsz = GetTextSize("X", font);
for(int i = 0; i < bytes; i++) {
int b = data[be ? i : bytes - i - 1];
if(b < 0) {
w.DrawText(x, y, String('?', 2 * bytes), font, SColorHighlight);
x += 2 * bytes * fsz.cx;
w.DrawText(x, y, "=", font);
x += fsz.cx;
w.DrawText(x, y, "?", font, Red);
return;
}
d = (d << 8) | (byte) b;
}
w.DrawText(x, y, FormatIntHex(d, 2 * bytes), font, SColorHighlight);
x += 2 * bytes * fsz.cx;
w.DrawText(x, y, "=", font);
x += fsz.cx;
String txt = FormatUnsigned(d);
w.DrawText(x, y, txt, font, Red);
x += GetTextSize(txt, font).cx;
w.DrawText(x, y, "=", font);
x += fsz.cx;
int q = d;
if(bytes == 1)
q = (int8) d;
else
if(bytes == 2)
q = (int16) d;
w.DrawText(x, y, FormatInt(q), font, Magenta);
}
void HexViewInfo::Paint(Draw& w)
{
Size sz = GetSize();
w.DrawRect(sz, SColorLtFace);
if(mode < 1 || empty)
return;
Size fsz = GetTextSize("X", font);
char h[17];
FormatHex(h, pos, longmode ? 16 : 8);
int xx = 0;
w.DrawText(xx, 0, h, font, SColorHighlight);
xx += (longmode ? 16 : 8) * fsz.cx;
w.DrawText(xx, 0, "=", font);
xx += fsz.cx;
w.DrawText(xx, 0, Format64(pos), font, Red);
xx += (longmode ? 22 : 12) * fsz.cx;
int y = 0;
int x = 0;
for(int q = 0; q < min(mode, 2); q++) {
x = xx;
if(q < 1)
PrintValue(w, x, y, 1, q);
x += 12 * fsz.cx;
PrintValue(w, x, y, 2, q);
x += 18 * fsz.cx;
PrintValue(w, x, y, 4, q);
x += 32 * fsz.cx;
y += fsz.cy;
}
char sh[200];
memset(sh, 0, sizeof(sh));
int i;
for(i = 0; i < 200; i++) {
if(data[i] < 0)
break;
sh[i] = data[i];
}
if(mode == 3)
w.DrawText(x, 0, ToUtf32(sh, i), font, Cyan, i);
if(mode < 2)
return;
String txt;
String ftxt;
i = 0;
for(;;) {
if(data[i] < 0) {
if((unsigned)i < sizeof(float))
ftxt = "?";
txt = "?";
break;
}
if((unsigned)i >= sizeof(double)) {
double h;
memcpy(&h, sh, sizeof(double));
txt = Sprintf("%.8g", h);
break;
}
if(i == sizeof(float)) {
float h;
memcpy(&h, sh, sizeof(float));
ftxt = Sprintf("%.6g", h);
}
sh[i] = data[i];
i++;
}
w.DrawText(0, fsz.cy, txt, font, Red);
w.DrawText(18 * fsz.cx, fsz.cy, ftxt, font, Red);
}
void HexViewInfo::SetMode(int _mode)
{
mode = _mode;
Height(min(mode, 2) * GetTextSize("X", CourierZ(12)).cy + 3);
Show(mode);
}
HexViewInfo::HexViewInfo()
{
SetMode(0);
AddFrame(TopSeparatorFrame());
AddFrame(RightSeparatorFrame());
font = CourierZ(12);
}
int HexView::Byte(int64 adr)
{
return 0;
}
void HexView::Paint(Draw& w)
{
Size sz = GetSize();
w.DrawRect(sz, SColorPaper);
if(!total) {
w.DrawText(Zx(10), Zx(10), "No data", ArialZ(20).Italic(), SRed());
return;
}
int y = 0;
uint64 adr = sc;
Buffer<char> hex(2 * columns), text(columns), mark(columns);
Buffer<int> hex_dx(2 * columns), text_dx(columns, fsz.cx);
while(y < sz.cy && adr < total) {
char h[17];
FormatHex(h, adr + start, IsLongMode() ? 16 : 8);
w.DrawText(0, y, h, font);
int x = (IsLongMode() ? 17 : 9) * fsz.cx;
int tx = x + columns * fcx3;
int hexi = 0;
int texti = 0;
uint64 adr0 = adr;
for(int q = columns; q-- && adr < total;) {
if(adr == cursor) {
w.DrawRect(x + fsz.cx * 3 * int(adr - adr0), y, fsz.cx * 2, fsz.cy, LtCyan);
w.DrawRect(tx + fsz.cx * int(adr - adr0), y, fsz.cx, fsz.cy, LtCyan);
}
int b = Byte(adr++);
hex[hexi] = b < 0 ? '?' : FormatHexDigit((b & 0xf0) >> 4);
hex_dx[hexi++] = fsz.cx;
hex[hexi] = b < 0 ? '?' : FormatHexDigit(b & 0x0f);
hex_dx[hexi++] = 2 * fsz.cx;
text[texti] = b >= 32 ? b : ' ';
mark[texti++] = b < 32 ? decode(b, '\a', 'a', '\b', 'b', '\t', 't', '\f', 'f',
'\r', 'r', '\n', 'n', '\v', 'v', '\0', '0',
'\1', '1', '.') : ' ';
}
w.DrawText(x, y, hex, font, SColorText(), hexi, hex_dx);
w.DrawText(tx, y, text, font, SColorText(), texti, text_dx);
w.DrawText(tx, y, mark, font, SColorMark(), texti, text_dx);
y += fsz.cy;
}
}
void HexView::MouseWheel(Point, int zdelta, dword)
{
sb.Wheel(zdelta);
}
void HexView::SetSb()
{
sbm = 0;
uint64 sz = total;
while((sz >> sbm) > (1 << 30))
sbm++;
sb.SetTotal(int(sz >> sbm) / columns + 2);
sb.SetPage(int(rows >> sbm));
sb.Set(int(sc >> sbm) / columns + 1);
}
void HexView::Layout()
{
Size sz = GetSize();
columns = fixed ? fixed : max(4, (sz.cx - (IsLongMode() ? 18 : 10) * fsz.cx) / (4 * fsz.cx));
rows = max(1, sz.cy / fsz.cy);
bytes = columns * rows;
SetSb();
}
void HexView::SetStart(uint64 start_)
{
start = start_;
Layout();
SetSb();
Refresh();
RefreshInfo();
}
void HexView::SetTotal(uint64 _total)
{
total = _total;
Layout();
SetSb();
Refresh();
RefreshInfo();
}
void HexView::SetSc(uint64 address)
{
sc = minmax(address, start, total);
SetSb();
Refresh();
}
void HexView::Scroll()
{
int64 q = (int64)(int)sb << sbm;
if(q == 0)
sc = 0;
else
sc = (q - 1) * columns + sc % columns;
Refresh();
}
void HexView::RefreshInfo()
{
if(total && (int64)cursor >= 0) {
info.SetPos(cursor + start, IsLongMode());
for(int i = 0; i < 80; i++)
info.Set(i, Byte(cursor + i));
}
else
info.SetEmpty();
}
void HexView::SetCursor(uint64 _cursor)
{
cursor = _cursor;
if(cursor > INT64_MAX - INT_MAX)
cursor = 0;
if(cursor >= total)
cursor = total - 1;
int q = int(sc % columns);
if(cursor >= sc + bytes)
sc = cursor - bytes + columns;
if(cursor < sc) {
sc = cursor;
}
if(sc > (uint64)q)
sc = (sc - q) / columns * columns + q;
if(sc >= total)
sc = total - 1;
SetSb();
Refresh();
RefreshInfo();
}
void HexView::LeftDown(Point p, dword)
{
int rowi = p.y / fsz.cy;
int x = (IsLongMode() ? 17 : 9) * fsz.cx;
int tx = x + columns * fcx3;
if(p.x >= x && p.x < tx) {
x = p.x - x;
int q = x / fcx3;
if(x - q * fcx3 < 2 * fsz.cx && q < columns) {
uint64 c = sc + rowi * columns + q;
if(c < total)
SetCursor(c);
}
}
else
if(p.x >= tx) {
int q = (p.x - tx) / fsz.cx;
if(q >= 0 && q < columns) {
uint64 c = sc + rowi * columns + q;
if(c < total)
SetCursor(c);
}
}
SetFocus();
}
bool HexView::Key(dword key, int)
{
int pg = max(columns, bytes - columns);
int q = int(sc % columns);
switch(key) {
case K_LEFT:
SetCursor(cursor - 1);
return true;
case K_RIGHT:
SetCursor(cursor + 1);
return true;
case K_UP:
SetCursor(cursor - columns);
return true;
case K_DOWN:
SetCursor(cursor + columns);
return true;
case K_PAGEUP:
SetSc(sc - pg);
SetCursor(cursor - pg);
return true;
case K_PAGEDOWN:
SetSc(sc + pg);
SetCursor(cursor + pg);
return true;
case K_CTRL_LEFT:
SetSc(sc - 1);
break;
case K_CTRL_RIGHT:
SetSc(sc + 1);
break;
case K_CTRL_UP:
SetSc(sc - columns);
break;
case K_CTRL_DOWN:
SetSc(sc + columns);
break;
case K_HOME:
SetCursor((cursor - q) / columns * columns + q);
break;
case K_END:
SetCursor((cursor - q) / columns * columns + q + columns - 1);
break;
case K_CTRL_HOME:
case K_CTRL_PAGEUP:
SetCursor(0);
break;
case K_CTRL_END:
case K_CTRL_PAGEDOWN:
SetCursor(total - 1);
break;
}
return MenuBar::Scan(WhenBar, key);
}
void HexView::SetColumns(int x)
{
FixedColumns(x);
}
void HexView::SetCharset(int chr)
{
Charset(chr);
}
void HexView::StdGoto(const String& s)
{
CParser p(s);
int n = 10;
if(p.Char2('0', 'x') || p.Char('$') || p.Char('#'))
n = 16;
if(p.IsNumber(n)) {
uint64 a = p.ReadNumber(n);
if(a < total) {
SetCursor(a);
SetSc(a);
return;
}
}
Exclamation("Invalid position!");
}
void HexView::Goto()
{
if(go.Execute() == IDOK)
WhenGoto((String)~go.text);
}
void HexView::ColumnsMenu(Bar& bar)
{
bar.Add("Auto", THISBACK1(SetColumns, 0))
.Radio(fixed == 0);
bar.Add("8", THISBACK1(SetColumns, 8))
.Radio(fixed == 8);
bar.Add("16", THISBACK1(SetColumns, 16))
.Radio(fixed == 16);
bar.Add("32", THISBACK1(SetColumns, 32))
.Radio(fixed == 32);
}
void HexView::SetInfo(int m)
{
info.SetMode(m);
}
void HexView::InfoMenu(Bar& bar)
{
bar.Add("None", THISBACK1(SetInfo, 0))
.Radio(info.GetMode() == 0);
bar.Add("Standard", THISBACK1(SetInfo, 1))
.Radio(info.GetMode() == 1);
bar.Add("Extended", THISBACK1(SetInfo, 2))
.Radio(info.GetMode() == 2);
bar.Add("Full", THISBACK1(SetInfo, 3))
.Radio(info.GetMode() == 3);
}
void HexView::CharsetMenu(Bar& bar)
{
for(int i = 1; i < CharsetCount(); i++)
bar.Add(CharsetName(i), THISBACK1(SetCharset, i))
.Radio(charset == i);
}
void HexView::StdMenu(Bar& bar)
{
bar.Add("Go to..", [=] { WhenGotoDlg(); })
.Key(K_CTRL_G);
bar.Add("Columns", THISBACK(ColumnsMenu));
bar.Add("Charset", THISBACK(CharsetMenu));
bar.Add("Position info", THISBACK(InfoMenu));
}
void HexView::RightDown(Point p, dword w)
{
LeftDown(p, w);
MenuBar::Execute(WhenBar);
}
HexView& HexView::SetFont(Font fnt)
{
font = fnt;
fsz = GetTextSize("X", font);
fcx3 = 3 * fsz.cx;
Layout();
Refresh();
SetSb();
return *this;
}
void HexView::SerializeSettings(Stream& s)
{
int version = 0;
s / version;
s / fixed;
s % charset;
int mode = info.GetMode();
s / mode;
info.SetMode(mode);
go.text.SerializeList(s);
}
HexView::HexView()
{
SetFont(CourierZ(12));
BackPaint();
charset = CHARSET_WIN1252;
sb <<= THISBACK(Scroll);
SetFrame(InsetFrame());
AddFrame(sb);
cursor = sc = 0;
total = 0;
fixed = 0;
SetSc(0);
SetCursor(0);
AddFrame(info);
info.SetMode(1);
WhenBar = THISBACK(StdMenu);
CtrlLayoutOKCancel(go, "Go to");
WhenGoto = THISBACK(StdGoto);
WhenGotoDlg = THISBACK(Goto);
}
}