aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2023-03-14 17:35:08 +0100
committerHugo Hörnquist <hugo@lysator.liu.se>2023-03-14 17:35:08 +0100
commitd7e7c6977a0376747269ad905cff1af18f85831d (patch)
tree0ac0dd252be34621c2e8a0d51889d1f80cbc1664
parentcode (diff)
downloadhex-viewer-d7e7c6977a0376747269ad905cff1af18f85831d.tar.gz
hex-viewer-d7e7c6977a0376747269ad905cff1af18f85831d.tar.xz
work
-rw-r--r--Makefile17
-rw-r--r--analyze-gz.c280
-rw-r--r--analyze_gz.c88
-rw-r--r--format.c188
-rw-r--r--format.h13
-rw-r--r--gzip.h77
-rw-r--r--hexdump_pretty.c125
-rw-r--r--hexdump_pretty.h37
-rw-r--r--ui.c116
9 files changed, 630 insertions, 311 deletions
diff --git a/Makefile b/Makefile
index 1221184..08d61cf 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,17 @@
-CFLAGS = -Wall -std=c11 -ggdb
+CFLAGS = -Wall -std=c11 -ggdb -D_POSIX_C_SOURCE=200809L
LDLIBS = -lncurses
-analyze-gc: analyze-gz.c
+.PHONY: all
+all: analyze_gz ui
+
+analyze_gz: analyze_gz.o hexdump_pretty.o
+ $(CC) $^ -o $@ $(LDLIBS)
+
+ui: ui.o format.o
+ $(CC) $^ -o $@ $(LDLIBS)
+
+analyze_gz.o: analyze_gz.c hexdump_pretty.h gzip.h
+hexdump_pretty.o: hexdump_pretty.c hexdump_pretty.h
+format.o: format.c format.h gzip.h
+ui.o: ui.c format.h
-ui: ui.c
diff --git a/analyze-gz.c b/analyze-gz.c
deleted file mode 100644
index a0c6d40..0000000
--- a/analyze-gz.c
+++ /dev/null
@@ -1,280 +0,0 @@
-#define _POSIX_C_SOURCE 200809L
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdbool.h>
-#include <assert.h>
-#include <ctype.h>
-
-#define ID1 31
-#define ID2 139
-
-enum compression_method {
- DEFLATE = 8,
-};
-
-enum flag {
- FTEXT = 1 << 0,
- FHCRC = 1 << 1,
- FEXTRA = 1 << 2,
- FNAME = 1 << 3,
- FCOMMENT = 1 << 4,
-};
-
-enum operating_system {
- FAT = 0,
- AMIGA,
- VMS,
- UNIX,
- CMS,
- ATARI_TOS,
- HPFS,
- MACINTOSH,
- Z_SYSTEM,
- CP_M,
- TOPS20,
- NTFS,
- QDOS,
- ACORN_RISCOS,
-};
-
-const char *os_str(enum operating_system os) {
- switch (os) {
- case FAT: return "FAT filesystem (MS-DOS, OS/2, NT/Win32)";
- case AMIGA: return "Amiga";
- case VMS: return "VMS (or OpenVMS)";
- case UNIX: return "Unix";
- case CMS: return "VM/CMS";
- case ATARI_TOS: return "Atari TOS";
- case HPFS: return "HPFS filesystem (OS/2, NT)";
- case MACINTOSH: return "Macintosh";
- case Z_SYSTEM: return "Z-System";
- case CP_M: return "CP/M";
- case TOPS20: return "TOPS-20";
- case NTFS: return "NTFS filesystem (NT)";
- case QDOS: return "QDOS";
- case ACORN_RISCOS: return "Acorn RISCOS";
- default: return "unknown";
- }
-}
-
-struct member {
- uint8_t id1, id2, cm, flg;
- uint32_t mtime;
- uint8_t xfl, os;
-} __attribute__((packed));
-
-
-enum color {
- BLACK = 0,
- RED,
- GREEN,
- YELLOW,
- BLUE,
- PURPLE,
- CYAN,
- WHITE,
-};
-
-
-struct segment {
- enum color c;
- size_t len;
- uint8_t *data;
-};
-
-enum color next_color(void) {
- static uint8_t cc = 0;
- cc += 1;
- cc %= 6;
- return cc + 1;
-}
-
-void color_put(enum color c) {
- printf("\x1b[0;3%im", c);
-}
-
-void color_reset(void) {
- printf("\x1b[m");
-}
-
-#define LINELEN 0x8
-struct segment line_segments[LINELEN];
-size_t file_idx = 0;
-size_t line_idx = 0;
-size_t current_segment = 0;
-
-void cleanup_line(void) {
- for (int i = 0; i < current_segment; i++) {
- free(line_segments[i].data);
- }
-}
-
-void put_byte(uint8_t byte) {
- static bool flip = 0;
- printf("%02x", byte);
- flip = !flip;
- if (! flip) {
- printf(" ");
- }
-}
-
-void flush_line() {
- printf("%06lx: ", file_idx);
- file_idx += LINELEN;
- for (int i = 0; i < current_segment; i++) {
- color_put(line_segments[i].c);
- for (int b = 0; b < line_segments[i].len; b++) {
- put_byte(line_segments[i].data[b]);
- }
- color_reset();
- }
- for (int i = 0; i < current_segment; i++) {
- color_put(line_segments[i].c);
- for (int b = 0; b < line_segments[i].len; b++) {
- uint8_t ch = line_segments[i].data[b];
- if (isprint(ch)) {
- printf("%c", ch);
- } else {
- printf(".");
- }
- }
- color_reset();
- }
- printf("\n");
-}
-
-void add_segment(struct segment segment) {
- line_segments[current_segment++] = segment;
- line_idx += segment.len;
- if (line_idx == LINELEN) {
- flush_line();
- cleanup_line();
- current_segment = 0;
- line_idx = 0;
- }
-}
-
-/*
- * Buf MUST be a malloc:ed buffer, which is invalidated on this call.
- */
-void write_chunk(uint8_t *buf, size_t len) {
- if (line_idx + len >= LINELEN) {
- enum color c = next_color();
- size_t len1 = LINELEN - line_idx,
- len2 = len - len1;
- uint8_t *buf1 = malloc(len1),
- *buf2 = malloc(len2);
- memcpy(buf1, buf, len1);
- memcpy(buf2, buf + len1, len2);
- free(buf);
- struct segment
- seg1 = {
- .c = c,
- .len = len1,
- .data = buf1,
- },
- seg2 = {
- .c = c,
- .len = len2,
- .data = buf2,
- };
- add_segment(seg1);
- add_segment(seg2);
- } else {
- struct segment seg = {
- .c = next_color(),
- .len = len,
- .data = buf,
- };
- add_segment(seg);
- }
-}
-
-void write_chunk_s(uint8_t *buf, size_t len) {
- assert (len >= 0);
- uint8_t *true_buf = malloc(len);
- memcpy(true_buf, buf, len);
- write_chunk(true_buf, len);
-}
-
-int main(int argc, char *argv[]) {
- if (argc == 1) {
- fprintf(stderr, "Usage: %s <filename.gz>\n", argv[0]);
- return 1;
- }
-
- FILE *f = fopen(argv[1], "rb");
- size_t len;
-
- struct member header;
- uint8_t *extra_fields = NULL;
- uint16_t crc16 = 0;
- char *filename = NULL;
- char *file_comment = NULL;
-
- len = fread(&header, sizeof(header), 1, f);
-
- if (len != 1) {
- fprintf(stderr, "Unexpected end of header\n");
- return 1;
- }
-
- write_chunk_s((uint8_t[2]) {header.id1, header.id2}, 2);
- write_chunk_s(&header.cm, 1);
- write_chunk_s(&header.flg, 1);
- {
- size_t s = sizeof(header.mtime);
- uint8_t *buf = malloc(s);
- memcpy(buf, &header.mtime, s);
- write_chunk(buf, s);
- }
- write_chunk_s(&header.xfl, 1);
- write_chunk_s(&header.os, 1);
-
- if (header.flg & FEXTRA) {
- uint16_t xlen;
- len = fread(&xlen, sizeof(xlen), 1, f);
- {
- uint8_t *buf = malloc(len);
- memcpy(buf, &xlen, len);
- write_chunk(buf, len);
- }
- extra_fields = malloc(xlen);
- len = fread(extra_fields, 1, xlen, f);
- write_chunk(extra_fields, xlen);
- }
-
- if (header.flg & FNAME) {
- size_t n;
- len = getdelim(&filename, &n, '\0', f);
- write_chunk((uint8_t*) filename, n);
- }
-
- if (header.flg & FCOMMENT) {
- size_t n;
- len = getdelim(&file_comment, &n, '\0', f);
- write_chunk((uint8_t*) file_comment, n);
- }
-
- if (header.flg & FHCRC) {
- len = fread(&crc16, sizeof(crc16), 1, f);
- {
- uint8_t *buf = malloc(len);
- memcpy(buf, &crc16, len);
- write_chunk(buf, len);
- }
- }
-
-// cleanup:
- if (extra_fields) free(extra_fields);
- if (filename) free(filename);
- if (file_comment) free(file_comment);
- flush_line();
- cleanup_line();
-
- printf("\n");
-
-
-}
diff --git a/analyze_gz.c b/analyze_gz.c
new file mode 100644
index 0000000..1ea0d78
--- /dev/null
+++ b/analyze_gz.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "hexdump_pretty.h"
+
+#include "gzip.h"
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) {
+ fprintf(stderr, "Usage: %s <filename.gz>\n", argv[0]);
+ return 1;
+ }
+
+ FILE *f = fopen(argv[1], "rb");
+ size_t len;
+
+ struct member header;
+ uint8_t *extra_fields = NULL;
+ uint16_t crc16 = 0;
+ char *filename = NULL;
+ char *file_comment = NULL;
+
+ len = fread(&header, sizeof(header), 1, f);
+
+ if (len != 1) {
+ fprintf(stderr, "Unexpected end of header\n");
+ return 1;
+ }
+
+ write_chunk_s((uint8_t[2]) {header.id1, header.id2}, 2);
+ write_chunk_s(&header.cm, 1);
+ write_chunk_s(&header.flg, 1);
+ {
+ size_t s = sizeof(header.mtime);
+ uint8_t *buf = malloc(s);
+ memcpy(buf, &header.mtime, s);
+ write_chunk(buf, s);
+ }
+ write_chunk_s(&header.xfl, 1);
+ write_chunk_s(&header.os, 1);
+
+ if (header.flg & FEXTRA) {
+ uint16_t xlen;
+ len = fread(&xlen, sizeof(xlen), 1, f);
+ {
+ uint8_t *buf = malloc(len);
+ memcpy(buf, &xlen, len);
+ write_chunk(buf, len);
+ }
+ extra_fields = malloc(xlen);
+ len = fread(extra_fields, 1, xlen, f);
+ write_chunk(extra_fields, xlen);
+ }
+
+ if (header.flg & FNAME) {
+ size_t n;
+ len = getdelim(&filename, &n, '\0', f);
+ write_chunk((uint8_t*) filename, n);
+ }
+
+ if (header.flg & FCOMMENT) {
+ size_t n;
+ len = getdelim(&file_comment, &n, '\0', f);
+ write_chunk((uint8_t*) file_comment, n);
+ }
+
+ if (header.flg & FHCRC) {
+ len = fread(&crc16, sizeof(crc16), 1, f);
+ {
+ uint8_t *buf = malloc(len);
+ memcpy(buf, &crc16, len);
+ write_chunk(buf, len);
+ }
+ }
+
+// cleanup:
+ if (extra_fields) free(extra_fields);
+ if (filename) free(filename);
+ if (file_comment) free(file_comment);
+ flush_line();
+ cleanup_line();
+
+ printf("\n");
+
+
+}
diff --git a/format.c b/format.c
new file mode 100644
index 0000000..cbd7265
--- /dev/null
+++ b/format.c
@@ -0,0 +1,188 @@
+#include "format.h"
+#include "gzip.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+struct segment empty_segment = {
+ .start = -1,
+ .end = -1,
+ .description = "No segment selected",
+};
+
+struct segment get_segment(void *mem, size_t len, ssize_t addr) {
+
+ if (addr < 0 || addr >= len) {
+ return empty_segment;
+ }
+
+
+ static char *buf = NULL;
+ if (buf != NULL) {
+ free(buf);
+ buf = NULL;
+ }
+ struct member *header = (struct member*) mem;
+
+ if (addr == 0) {
+ return (struct segment) {
+ .start = 0,
+ .end = 1,
+ .description = "ID1 = 31"
+ };
+ }
+ if (addr == 1) {
+ return (struct segment) {
+ .start = 1,
+ .end = 2,
+ .description = "ID2 = 139",
+ };
+ }
+ if (addr == 2) {
+ return (struct segment) {
+ .start = 2,
+ .end = 3,
+ .description = "CM (Compression Method)\n"
+ "CM = 8 is defalte",
+ };
+ }
+ if (addr == 3) {
+ buf = malloc(1000);
+ buf[0] = '\0';
+ for (int i = 0; i < 5; i++) {
+ if (header->flg & (1 << i)) {
+ strcat(buf, "- ");
+ strcat(buf, flag_str(1<<i));
+ strcat(buf, "\n");
+ }
+ }
+ return (struct segment) {
+ .start = 3,
+ .end = 4,
+ .description = buf,
+ };
+ }
+ if (addr >= 4 && addr < 8) {
+ buf = malloc(1000);
+ sprintf(buf, "Mtime=%i", header->mtime);
+ return (struct segment) {
+ .start = 4,
+ .end = 8,
+ .description = buf,
+ };
+ }
+ if (addr == 8) {
+ return (struct segment) {
+ .start = 8,
+ .end = 9,
+ .description = "XFL",
+ };
+ }
+ if (addr == 9) {
+ buf = malloc(1000);
+ sprintf(buf, "OS: %s\n", os_str(header->os));
+ return (struct segment) {
+ .start = 9,
+ .end = 10,
+ .description = buf,
+ };
+ }
+
+ void *ptr = ((struct member*) mem) + 1;
+
+ if (header->flg & FEXTRA) {
+ uint16_t xlen = *((uint16_t*) ptr);
+ if (mem + addr == ptr || mem + addr == ptr + 1) {
+ return (struct segment) {
+ .start = ptr - mem,
+ .end = ptr - mem + 1,
+ .description = "XLEN",
+ };
+ }
+ ptr = ((uint16_t*) ptr) + 1;
+ // if (mem + addr >= ptr && mem + addr < xlen) {
+ if (ptr - mem + addr < 2) {
+ return (struct segment) {
+ .start = ptr - mem,
+ .end = ptr - mem + xlen,
+ .description = "XLEN bytes of extra data",
+ };
+ }
+ ptr = ((uint8_t*) ptr) + 1 + xlen;
+ }
+
+ if (header->flg & FNAME) {
+ void *c = memchr(ptr, '\0', (ptr - mem) + len);
+ size_t start = ptr - mem;
+ size_t end = c - mem;
+ ptr = ((uint8_t*) c) + 1;
+ if (addr < c - mem + 1) {
+ return (struct segment) {
+ .start = start,
+ .end = end + 1,
+ .description = "Original filename",
+ };
+ }
+ }
+
+ if (header->flg & FCOMMENT) {
+ void *c = memchr(ptr, '\0', (ptr - mem) + len);
+ ptr = ((uint8_t*) c) + 1;
+ if (addr < c - mem + 1) {
+ size_t start = ptr - mem;
+ size_t end = c - mem;
+ return (struct segment) {
+ .start = start,
+ .end = end + 1,
+ .description = "File comment",
+ };
+ }
+ }
+
+ if (header->flg & FHCRC) {
+ if (addr < ptr - mem + 2) {
+ buf = malloc(1000);
+ fprintf(buf, "CRC16=" PRIu16, *((uint16_t*) ptr));
+ return (struct segment) {
+ .start = ptr - mem,
+ .end = ptr - mem + 2,
+ .description = buf,
+ };
+ }
+ ptr = (uint16_t*) ptr + 1;
+ }
+
+ if (len - addr < 4) {
+ buf = malloc(1000);
+ fprintf(buf, "ISIZE" PRIu32, *(((uint32_t*) ((uint8_t*) (mem + len))) - 1));
+ return (struct segment) {
+ .start = len - 4,
+ .end = len,
+ .description = buf,
+ };
+ }
+
+ if (len - addr - 4 < 4) {
+ buf = malloc(1000);
+ fprintf(buf, "CRC32" PRIu32, *(((uint32_t*) ((uint8_t*) (mem + len))) - 2));
+ return (struct segment) {
+ .start = len - 8,
+ .end = len - 4,
+ .description = buf,
+ };
+ }
+
+ if (ptr - mem <= addr && addr < ptr - mem + len - 8) {
+ return (struct segment) {
+ .start = ptr - mem,
+ .end = len - 8,
+ .description = "ZLIB compressed payload",
+ };
+ }
+
+
+ return empty_segment;
+
+}
diff --git a/format.h b/format.h
new file mode 100644
index 0000000..b09cb2f
--- /dev/null
+++ b/format.h
@@ -0,0 +1,13 @@
+#ifndef FILE_FORMAT_H
+#define FILE_FORMAT_H
+
+#include <sys/types.h>
+
+struct segment {
+ size_t start, end;
+ const char *description;
+};
+
+struct segment get_segment(void *mem, size_t len, ssize_t addr);
+
+#endif /* FILE_FORMAT_H */
diff --git a/gzip.h b/gzip.h
new file mode 100644
index 0000000..e5d5947
--- /dev/null
+++ b/gzip.h
@@ -0,0 +1,77 @@
+#ifndef GZIP_H
+#define GZIP_H
+
+#include <stdint.h>
+
+/* RFC 1952 */
+
+#define ID1 31
+#define ID2 139
+
+enum compression_method {
+ DEFLATE = 8,
+};
+
+enum flag {
+ FTEXT = 1 << 0,
+ FHCRC = 1 << 1,
+ FEXTRA = 1 << 2,
+ FNAME = 1 << 3,
+ FCOMMENT = 1 << 4,
+};
+
+const char *flag_str (enum flag f) {
+ switch (f) {
+ case FTEXT: return "Content is probably text";
+ case FHCRC: return "CRC16 is present";
+ case FEXTRA: return "Extra field is populated";
+ case FNAME: return "A file name is present";
+ case FCOMMENT: return "A comment is present";
+ default: return "unknown flag";
+ }
+}
+
+enum operating_system {
+ FAT = 0,
+ AMIGA,
+ VMS,
+ UNIX,
+ CMS,
+ ATARI_TOS,
+ HPFS,
+ MACINTOSH,
+ Z_SYSTEM,
+ CP_M,
+ TOPS20,
+ NTFS,
+ QDOS,
+ ACORN_RISCOS,
+};
+
+const char *os_str(enum operating_system os) {
+ switch (os) {
+ case FAT: return "FAT filesystem (MS-DOS, OS/2, NT/Win32)";
+ case AMIGA: return "Amiga";
+ case VMS: return "VMS (or OpenVMS)";
+ case UNIX: return "Unix";
+ case CMS: return "VM/CMS";
+ case ATARI_TOS: return "Atari TOS";
+ case HPFS: return "HPFS filesystem (OS/2, NT)";
+ case MACINTOSH: return "Macintosh";
+ case Z_SYSTEM: return "Z-System";
+ case CP_M: return "CP/M";
+ case TOPS20: return "TOPS-20";
+ case NTFS: return "NTFS filesystem (NT)";
+ case QDOS: return "QDOS";
+ case ACORN_RISCOS: return "Acorn RISCOS";
+ default: return "unknown";
+ }
+}
+
+struct member {
+ uint8_t id1, id2, cm, flg;
+ uint32_t mtime;
+ uint8_t xfl, os;
+} __attribute__((packed));
+
+#endif /* GZIP_H */
diff --git a/hexdump_pretty.c b/hexdump_pretty.c
new file mode 100644
index 0000000..d082c0b
--- /dev/null
+++ b/hexdump_pretty.c
@@ -0,0 +1,125 @@
+#include "hexdump_pretty.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LINELEN 0x8
+
+static struct segment line_segments[LINELEN];
+static size_t file_idx = 0;
+static size_t line_idx = 0;
+static size_t current_segment = 0;
+
+
+enum color next_color(void) {
+ static uint8_t cc = 0;
+ cc += 1;
+ cc %= 6;
+ return cc + 1;
+}
+
+void color_put(enum color c) {
+ printf("\x1b[0;3%im", c);
+}
+
+void color_reset(void) {
+ printf("\x1b[m");
+}
+
+void cleanup_line(void) {
+ for (int i = 0; i < current_segment; i++) {
+ free(line_segments[i].data);
+ }
+}
+
+void put_byte(uint8_t byte) {
+ static bool flip = 0;
+ printf("%02x", byte);
+ flip = !flip;
+ if (! flip) {
+ printf(" ");
+ }
+}
+
+void flush_line() {
+ printf("%06lx: ", file_idx);
+ file_idx += LINELEN;
+ for (int i = 0; i < current_segment; i++) {
+ color_put(line_segments[i].c);
+ for (int b = 0; b < line_segments[i].len; b++) {
+ put_byte(line_segments[i].data[b]);
+ }
+ color_reset();
+ }
+ for (int i = 0; i < current_segment; i++) {
+ color_put(line_segments[i].c);
+ for (int b = 0; b < line_segments[i].len; b++) {
+ uint8_t ch = line_segments[i].data[b];
+ if (isprint(ch)) {
+ printf("%c", ch);
+ } else {
+ printf(".");
+ }
+ }
+ color_reset();
+ }
+ printf("\n");
+}
+
+void add_segment(struct segment segment) {
+ line_segments[current_segment++] = segment;
+ line_idx += segment.len;
+ if (line_idx == LINELEN) {
+ flush_line();
+ cleanup_line();
+ current_segment = 0;
+ line_idx = 0;
+ }
+}
+
+/*
+ * Buf MUST be a malloc:ed buffer, which is invalidated on this call.
+ */
+void write_chunk(uint8_t *buf, size_t len) {
+ if (line_idx + len >= LINELEN) {
+ enum color c = next_color();
+ size_t len1 = LINELEN - line_idx,
+ len2 = len - len1;
+ uint8_t *buf1 = malloc(len1),
+ *buf2 = malloc(len2);
+ memcpy(buf1, buf, len1);
+ memcpy(buf2, buf + len1, len2);
+ free(buf);
+ struct segment
+ seg1 = {
+ .c = c,
+ .len = len1,
+ .data = buf1,
+ },
+ seg2 = {
+ .c = c,
+ .len = len2,
+ .data = buf2,
+ };
+ add_segment(seg1);
+ add_segment(seg2);
+ } else {
+ struct segment seg = {
+ .c = next_color(),
+ .len = len,
+ .data = buf,
+ };
+ add_segment(seg);
+ }
+}
+
+void write_chunk_s(uint8_t *buf, size_t len) {
+ assert (len >= 0);
+ uint8_t *true_buf = malloc(len);
+ memcpy(true_buf, buf, len);
+ write_chunk(true_buf, len);
+}
diff --git a/hexdump_pretty.h b/hexdump_pretty.h
new file mode 100644
index 0000000..c804f37
--- /dev/null
+++ b/hexdump_pretty.h
@@ -0,0 +1,37 @@
+#ifndef HEXDUMP_PRETTY_H
+#define HEXDUMP_PRETTY_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+enum color {
+ BLACK = 0,
+ RED,
+ GREEN,
+ YELLOW,
+ BLUE,
+ PURPLE,
+ CYAN,
+ WHITE,
+};
+
+
+
+struct segment {
+ enum color c;
+ size_t len;
+ uint8_t *data;
+};
+
+
+enum color next_color(void);
+void color_put(enum color c);
+void color_reset(void);
+void cleanup_line(void);
+void put_byte(uint8_t byte);
+void flush_line();
+void add_segment(struct segment segment);
+void write_chunk(uint8_t *buf, size_t len);
+void write_chunk_s(uint8_t *buf, size_t len);
+
+#endif /* HEXDUMP_PRETTY_H */
diff --git a/ui.c b/ui.c
index f114a41..9ac6965 100644
--- a/ui.c
+++ b/ui.c
@@ -11,12 +11,19 @@
#include <ncurses.h>
-#define LINE_LEN 0x10
+#include "format.h"
+
+#define LINE_LEN 0x10 /* Number of bytes in a line */
+
+#define LINENO_DIGITS 8 /* length of line numbers */
+#define LINENO_WIDTH (LINENO_DIGITS + 2) /* for padding */
+
+#define INFO_HEIGHT 10 /* Height of the info panel */
// int screen_height, screen_width;
struct screen {
- WINDOW *lineno, *hex, *chr;
+ WINDOW *lineno, *hex, *chr, *info;
int top_address;
void *mem;
size_t mem_len;
@@ -32,47 +39,81 @@ void draw_lines() {
}
}
-void draw_hex() {
+void draw_hex(struct segment *current) {
+
for (int y = 0; y < LINES; y++) {
for (int x = 0; x < LINE_LEN; x++) {
+ size_t addr = screen.top_address + y * LINE_LEN + x;
+ if (addr < 0 || addr >= screen.mem_len) continue;
+ if (current->start <= addr && addr < current->end) {
+ wattron(screen.hex, COLOR_PAIR(1));
+ }
if (screen.hy == y && screen.hx == x) {
wattron(screen.hex, A_REVERSE);
}
mvwprintw(screen.hex, y, x * 2 + (x/2), "%02x",
- 0xFF & ((char*) screen.mem)[screen.top_address + y * LINE_LEN + x]);
+ 0xFF & ((char*) screen.mem)[addr]);
if (screen.hy == y && screen.hx == x) {
wattroff(screen.hex, A_REVERSE);
}
+ if (current->start <= addr && addr < current->end) {
+ wattroff(screen.hex, COLOR_PAIR(1));
+ }
}
wrefresh(screen.hex);
}
}
-void draw_chr() {
+void draw_chr(struct segment *current) {
for (int y = 0; y < LINES; y++) {
for (int x = 0; x < LINE_LEN; x++) {
+ size_t addr = screen.top_address + y * LINE_LEN + x;
+ if (addr < 0 || addr >= screen.mem_len) continue;
+ if (current->start <= addr && addr < current->end) {
+ wattron(screen.chr, COLOR_PAIR(1));
+ }
if (screen.hy == y && screen.hx == x) {
wattron(screen.chr, A_REVERSE);
}
- char c = ((char*) screen.mem)[screen.top_address + y * LINE_LEN + x];
+ char c = ((char*) screen.mem)[addr];
mvwprintw(screen.chr, y, x, "%c", isprint(c) ? c : '.');
if (screen.hy == y && screen.hx == x) {
wattroff(screen.chr, A_REVERSE);
}
+ if (current->start <= addr && addr < current->end) {
+ wattroff(screen.chr, COLOR_PAIR(1));
+ }
}
wrefresh(screen.chr);
}
}
+void draw_info(struct segment *current) {
+ werase(screen.info);
+ wmove(screen.info, 0, 0);
+ whline(screen.info, '-', COLS);
+
+ // size_t mem_addr = screen.top_address + screen.hy * LINE_LEN + screen.hx;
+ mvwprintw(screen.info, 1, 0, current->description);
+
+
+ wrefresh(screen.info);
+}
+
void draw_screen() {
+ struct segment current = get_segment(
+ screen.mem,
+ screen.mem_len,
+ screen.top_address + screen.hy * LINE_LEN + screen.hx);
draw_lines();
- draw_hex();
- draw_chr();
+ draw_hex(&current);
+ draw_chr(&current);
+ draw_info(&current);
/* TODO end at end of file */
}
-int main() {
+int main(int argc, char *argv[]) {
/* Terminal supporting mouse movements */
setenv("TERM", "xterm-1003", true);
@@ -84,16 +125,28 @@ int main() {
curs_set(0);
start_color();
-
- // getmaxyx(stdscr, screen_height, screen_width);
+ init_pair(1, COLOR_RED, COLOR_BLACK);
keypad(stdscr, true);
- screen.lineno = newwin(0, 10, 0, 0);
- screen.hex = newwin(0, (int) ceil(LINE_LEN * 2.5), 0, 10);
- screen.chr = newwin(0, LINE_LEN, 0, 10 + (int) ceil(LINE_LEN * 2.5));
+ const int HEX_WIDTH = (int) ceil(LINE_LEN * 2.5);
+
+ {
+ int h = LINES - INFO_HEIGHT;
+ screen.lineno = newwin(h, LINENO_WIDTH, 0, 0);
+ screen.hex = newwin(h, HEX_WIDTH, 0, LINENO_WIDTH);
+ screen.chr = newwin(h, LINE_LEN, 0, LINENO_WIDTH + HEX_WIDTH);
+ screen.info = newwin(0, 0, h, 0);
+ }
+
+ char *filename;
+ if (argc == 1) {
+ filename = "payload.gz";
+ } else {
+ filename = argv[1];
+ }
- int fd = open("payload.gz", O_RDONLY);
+ int fd = open(filename, O_RDONLY);
struct stat statbuf;
if (fstat(fd, &statbuf) == -1) {
goto end;
@@ -110,11 +163,11 @@ int main() {
int ch;
MEVENT event;
- while (1) {
+ while (true) {
ch = wgetch(stdscr);
switch (ch) {
case KEY_MOUSE:
- wmove(stdscr, 0, 0);
+ // wmove(stdscr, 0, 0);
switch (getmouse(&event)) {
case OK:
if (event.bstate & BUTTON4_PRESSED) {
@@ -124,12 +177,17 @@ int main() {
screen.top_address += LINE_LEN;
}
- if (event.x >= 10 && event.x < 10 + (int) ceil(LINE_LEN * 2.5)) {
- screen.hx = (int) ((event.x - 10) / 2.5);
- screen.hy = event.y;
- } else if (event.x >= 10 + (int) ceil(LINE_LEN * 2.5) && event.x < (int) ceil(LINE_LEN * 2.5) + 10 + LINE_LEN) {
- screen.hx = event.x - (10 + (int) ceil(LINE_LEN * 2.5));
- screen.hy = event.y;
+ if (event.y >= 0 && event.y < LINES - INFO_HEIGHT) {
+ if (event.x >= LINENO_WIDTH && event.x < LINENO_WIDTH + HEX_WIDTH) {
+ screen.hx = (int) ((event.x - LINENO_WIDTH) / 2.5);
+ screen.hy = event.y;
+ } else if (event.x >= LINENO_WIDTH + HEX_WIDTH && event.x < HEX_WIDTH + LINENO_WIDTH + LINE_LEN) {
+ screen.hx = event.x - (LINENO_WIDTH + HEX_WIDTH);
+ screen.hy = event.y;
+ } else {
+ screen.hx = -1;
+ screen.hy = -1;
+ }
} else {
screen.hx = -1;
screen.hy = -1;
@@ -141,16 +199,17 @@ int main() {
// wprintw(win, "err");
break;
}
+
draw_screen();
refresh();
break;
case KEY_RESIZE:
- wresize(screen.lineno, LINES, 0);
- wresize(screen.hex, LINES, 0);
- wresize(screen.chr, LINES, 0);
+ wresize(screen.lineno, LINES - INFO_HEIGHT, 0);
+ wresize(screen.hex, LINES - INFO_HEIGHT, 0);
+ wresize(screen.chr, LINES - INFO_HEIGHT, 0);
draw_screen();
- mvprintw(0, 0, "%ix%i", COLS, LINES);
- refresh();
+ // mvprintw(0, 0, "%ix%i", COLS, LINES);
+ // refresh();
break;
case KEY_ENTER:
goto end;
@@ -162,6 +221,7 @@ end:
delwin(screen.lineno);
delwin(screen.hex);
delwin(screen.chr);
+ delwin(screen.info);
endwin();
return 0;
}