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
|
(*
* Copyright (c) 2015 Trevor Summers Smith <trevorsummerssmith@gmail.com>
* Copyright (c) 2014 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)
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 (* Char.code '0' *)
| 'A'..'F' -> Char.code c - 55 (* Char.code 'A' + 10 *)
| 'a'..'f' -> Char.code c - 87 (* Char.code 'a' + 10 *)
| _ -> 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
(* Allocate just once for to_cstruct *)
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 (* row width in # chars *)
let hex_len = char_len * 2 in (* row width in # hex chars *)
(* Buf length is roughly 4... could put this in exactly but very brittle *)
let buf = Buffer.create ((String.length s) * 4) in
let ( <= ) buf s = Buffer.add_string buf s in
(* Create three columns -- row #, hex and ascii chars*)
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
(* First column is row number *)
if print_row_numbers then
buf <= Printf.sprintf "%.8d: " row;
(* Row length is hex_length, unless we are on the last row and we
have less than hex_length left *)
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
(* Second column is the hex *)
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;
(* This is only needed for the last row -- pad if less than len *)
if last_row then
let missed_chars = hex_len - row_len in
let pad = missed_chars in
(* Every four chars add spacing *)
let pad = pad + (missed_chars / 4) in
buf <= Printf.sprintf "%s" (String.make pad ' ')
else ();
(* Third column is ascii *)
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
|