1/*
2
3    Minimum Profit - A Text Editor
4    Hexadecimal viewer.
5
6    ttcdt <dev@triptico.com> et al.
7
8    This software is released into the public domain.
9    NO WARRANTY. See file LICENSE for details.
10
11*/
12
13/** hexadecimal viewer object **/
14
15global mp_hex_view = new(mp_base, {
16        name:           '<hex view>',
17        offset:         0,
18        tx:             0,
19        bpl:            8,
20        data:           '',
21        f_offset:       0,
22        f_size:         0,
23        fd:             NULL,
24
25        get_status: sub (hex) {
26            sprintf("%s - 0x%06x (%d)", name, offset, offset);
27        },
28        init:       sub (hex) {
29            if ((fd = open(name, "rb")) == NULL)
30                hex = NULL;
31
32            name = sprintf(L("<hex view of %s>"), name);
33
34            return hex;
35        },
36        keypress:   sub (hex, keycode) {
37            if (keycode == 'cursor-down')
38                offset += bpl;
39            else
40            if (keycode == 'cursor-up')
41                offset -= bpl;
42            else
43            if (keycode == 'page-down' || keycode == 'mouse-wheel-down')
44                offset += bpl * (mp.window.ty - 1);
45            else
46            if (keycode == 'page-up' || keycode == 'mouse-wheel-up')
47                offset -= bpl * (mp.window.ty - 1);
48            else
49            if (keycode == 'home')
50                offset = 0;
51            else
52            if (keycode == 'end') {
53                fseek(fd, 0, 2);
54                offset = ftell(fd);
55            }
56
57            if (offset < 0)
58                offset = 0;
59
60            fseek(fd, 0, 2);
61            if (offset >= ftell(fd))
62                offset = ftell(fd);
63
64            return hex;
65        },
66        render:     sub (hex) {
67            local out = [];
68            local o;
69
70            if (tx != mp.window.tx) {
71                /* calculate bytes per line */
72                bpl = 100;
73
74                while ((12 + (bpl * 4)) > mp.window.tx)
75                    bpl -= 1;
76
77                tx = mp.window.tx;
78            }
79
80            /* round offset */
81            offset -= offset % bpl;
82
83            fseek(fd, offset, 0);
84
85            o = offset;
86
87            while (size(out) < mp.window.ty) {
88                local ov, nv, av, n, c;
89
90                nv = [];
91                av = [
92                    mp.colors.word2.attr,
93                    ' | '
94                ];
95                ov = [
96                    mp.colors.word1.attr,
97                    sprintf(" %06X |", ftell(fd))
98                ];
99
100                for (n = 0; n < bpl; n += 1) {
101                    local a = 0;
102
103                    if ((c = getchar(fd)) == NULL) {
104                        n -= 1;
105                        break;
106                    }
107
108                    if (o >= f_offset && o < f_offset + f_size)
109                        a = mp.colors.search.attr;
110                    else
111                        a = mp.colors.normal.attr;
112
113                    if (o == f_offset)
114                        push(nv, mp.colors.normal.attr, ' ',
115                            a, sprintf("%02X", ord(c)));
116                    else
117                        push(nv, a, sprintf(" %02X", ord(c)));
118
119                    if (ord(c) == 0x0a)
120                        c = mp.unicode("pilcrow");
121                    else
122                    if (ord(c) < 32 || ord(c) > 126)
123                        c = mp.unicode("middledot");
124
125                    push(av, a, c);
126
127                    o += 1;
128                }
129
130                while (n < bpl) {
131                    push(nv, mp.colors.normal.attr, '   ');
132                    push(av, mp.colors.word2.attr,  ' ');
133                    n += 1;
134                }
135
136                push(out, ov->join(nv)->join(av));
137
138                if (c == NULL)
139                    break;
140            }
141
142            while (size(out) < mp.window.ty)
143                push(out, []);
144
145            return out;
146        },
147        actions:    {
148            seek_next:  sub (hex) {
149                fseek(hex.fd, hex.f_offset + 1);
150
151                mp.busy(1);
152                local found = mp_c.search_hex(hex.fd, hex.data);
153                mp.busy(0);
154
155                if (found) {
156                    hex.f_offset  = ftell(hex.fd);
157                    hex.f_size    = hex.data->size() / 2;
158                    hex.offset    = hex.f_offset;
159                }
160                else
161                    mp.alert(L("Not found."));
162            },
163
164            seek:       sub (hex) {
165                local t = mp.form(
166                    [
167                        {
168                            label:   L("Hex string to seek") + ':',
169                            type:    'text',
170                            history: 'search-hex'
171                        }
172                    ]
173                );
174
175                if (t != NULL) {
176                    hex.data = t[0];
177                    hex.f_offset = hex.offset - 1;
178                    hex->actions.seek_next();
179                }
180            }
181        },
182        keycodes:   {
183            "ctrl-f"    => 'seek',
184            "f3"        => 'seek_next'
185        }
186    }
187);
188