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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
type t = [`Hex of string]
let invalid_arg fmt =
Printf.ksprintf (fun str -> raise (Invalid_argument str)) fmt
let hexa = "0123456789abcdef"
and hexa1 =
"0000000000000000111111111111111122222222222222223333333333333333\
4444444444444444555555555555555566666666666666667777777777777777\
88888888888888889999999999999999aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb\
ccccccccccccccccddddddddddddddddeeeeeeeeeeeeeeeeffffffffffffffff"
and hexa2 =
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
let char_is_printable chr =
chr >= ' ' && chr <= '~'
let of_char c =
let x = Char.code c in
hexa.[x lsr 4], hexa.[x land 0xf]
let to_char x y =
let code c = match c with
| '0'..'9' -> Char.code c - 48
| 'A'..'F' -> Char.code c - 55
| 'a'..'f' -> Char.code c - 87
| _ -> invalid_arg "Hex.to_char: %d is an invalid char" (Char.code c)
in
Char.chr (code x lsl 4 + code y)
let of_string_fast s =
let len = String.length s in
let buf = Bytes.create (len * 2) in
for i = 0 to len - 1 do
Bytes.unsafe_set buf (i * 2)
(String.unsafe_get hexa1 (Char.code (String.unsafe_get s i)));
Bytes.unsafe_set buf (succ (i * 2))
(String.unsafe_get hexa2 (Char.code (String.unsafe_get s i)));
done;
`Hex (Bytes.to_string buf)
let of_helper ~ignore (next : int -> char) len =
let buf = Buffer.create len in
for i = 0 to len - 1 do
let c = next i in
if List.mem c ignore then ()
else
let x,y = of_char c in
Buffer.add_char buf x;
Buffer.add_char buf y;
done;
`Hex (Buffer.contents buf)
let of_string ?(ignore = []) s =
match ignore with
| [] -> of_string_fast s
| ignore -> of_helper ~ignore (fun i -> s.[i]) (String.length s)
let of_bytes ?ignore b =
of_string ?ignore (Bytes.to_string b)
let to_helper ~empty_return ~create ~set (`Hex s) =
if s = "" then empty_return
else
let n = String.length s in
let buf = create (n/2) in
let rec aux i j =
if i >= n then ()
else if j >= n then invalid_arg "Hex conversion: Hex string cannot have an odd number of characters."
else (
set buf (i/2) (to_char s.[i] s.[j]);
aux (j+1) (j+2)
)
in
aux 0 1;
buf
let to_bytes hex =
to_helper ~empty_return:Bytes.empty ~create:Bytes.create ~set:Bytes.set hex
let to_string hex = Bytes.to_string @@ to_bytes hex
let of_cstruct ?(ignore=[]) cs =
let open Cstruct in
of_helper
~ignore
(fun i -> Bigarray.Array1.get cs.buffer (cs.off+i))
cs.len
let empty_cstruct = Cstruct.of_string ""
let to_cstruct hex =
to_helper
~empty_return:empty_cstruct ~create:Cstruct.create ~set:Cstruct.set_char hex
let of_bigstring ?(ignore=[]) buf =
of_helper
~ignore
(Bigarray.Array1.get buf)
(Bigarray.Array1.dim buf)
let to_bigstring hex =
to_helper
~empty_return:empty_cstruct.buffer
~create:Bigarray.(Array1.create char c_layout)
~set:Bigarray.Array1.set hex
let hexdump_s ?(print_row_numbers=true) ?(print_chars=true) (`Hex s) =
let char_len = 16 in
let hex_len = char_len * 2 in
let buf = Buffer.create ((String.length s) * 4) in
let ( <= ) buf s = Buffer.add_string buf s in
let n = String.length s in
let rows = (n / hex_len) + (if n mod hex_len = 0 then 0 else 1) in
for row = 0 to rows-1 do
let last_row = row = rows-1 in
if print_row_numbers then
buf <= Printf.sprintf "%.8d: " row;
let row_len = if last_row then
(let rem = n mod hex_len in
if rem = 0 then hex_len else rem)
else hex_len in
for i = 0 to row_len-1 do
if i mod 4 = 0 && i <> 0 then buf <= Printf.sprintf " ";
let i = i + (row * hex_len) in
buf <= Printf.sprintf "%c" (String.get s i)
done;
if last_row then
let missed_chars = hex_len - row_len in
let pad = missed_chars in
let pad = pad + (missed_chars / 4) in
buf <= Printf.sprintf "%s" (String.make pad ' ')
else ();
if print_chars then begin
buf <= " ";
let rec aux i j =
if i > row_len - 2 then ()
else begin
let pos = i + (row * hex_len) in
let pos' = pos + 1 in
let c = to_char (String.get s pos) (String.get s pos') in
if char_is_printable c then
buf <= Printf.sprintf "%c" c
else
buf <= ".";
aux (j+1) (j+2)
end
in
aux 0 1;
end;
buf <= "\n";
done;
Buffer.contents buf
let hexdump ?print_row_numbers ?print_chars hex =
Printf.printf "%s" (hexdump_s ?print_row_numbers ?print_chars hex)
let pp ppf (`Hex hex) =
Format.pp_print_string ppf hex
let show (`Hex hex) = hex