aboutsummaryrefslogtreecommitdiff
path: root/hexdump_pretty.c
blob: d082c0b6c455ad801e7f308575057dba342b9355 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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);
}