123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191(*
* 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.
*)typet=[`Hexofstring]letinvalid_argfmt=Printf.ksprintf(funstr->raise(Invalid_argumentstr))fmtlethexa="0123456789abcdef"andhexa1="0000000000000000111111111111111122222222222222223333333333333333\
4444444444444444555555555555555566666666666666667777777777777777\
88888888888888889999999999999999aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb\
ccccccccccccccccddddddddddddddddeeeeeeeeeeeeeeeeffffffffffffffff"andhexa2="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"letchar_is_printablechr=chr>=' '&&chr<='~'letof_charc=letx=Char.codecinhexa.[xlsr4],hexa.[xland0xf]letto_charxy=letcodec=matchcwith|'0'..'9'->Char.codec-48(* Char.code '0' *)|'A'..'F'->Char.codec-55(* Char.code 'A' + 10 *)|'a'..'f'->Char.codec-87(* Char.code 'a' + 10 *)|_->invalid_arg"Hex.to_char: %d is an invalid char"(Char.codec)inChar.chr(codexlsl4+codey)letof_string_fasts=letlen=String.lengthsinletbuf=Bytes.create(len*2)infori=0tolen-1doBytes.unsafe_setbuf(i*2)(String.unsafe_gethexa1(Char.code(String.unsafe_getsi)));Bytes.unsafe_setbuf(succ(i*2))(String.unsafe_gethexa2(Char.code(String.unsafe_getsi)));done;`Hex(Bytes.to_stringbuf)letof_helper~ignore(next:int->char)len=letbuf=Buffer.createleninfori=0tolen-1doletc=nextiinifList.memcignorethen()elseletx,y=of_charcinBuffer.add_charbufx;Buffer.add_charbufy;done;`Hex(Buffer.contentsbuf)letof_string?(ignore=[])s=matchignorewith|[]->of_string_fasts|ignore->of_helper~ignore(funi->s.[i])(String.lengths)letof_bytes?ignoreb=of_string?ignore(Bytes.to_stringb)letto_helper~empty_return~create~set(`Hexs)=ifs=""thenempty_returnelseletn=String.lengthsinletbuf=create(n/2)inletrecauxij=ifi>=nthen()elseifj>=ntheninvalid_arg"Hex conversion: Hex string cannot have an odd number of characters."else(setbuf(i/2)(to_chars.[i]s.[j]);aux(j+1)(j+2))inaux01;bufletto_byteshex=to_helper~empty_return:Bytes.empty~create:Bytes.create~set:Bytes.sethexletto_stringhex=Bytes.to_string@@to_byteshexletof_cstruct?(ignore=[])cs=letopenCstructinof_helper~ignore(funi->Bigarray.Array1.getcs.buffer(cs.off+i))cs.len(* Allocate just once for to_cstruct *)letempty_cstruct=Cstruct.of_string""letto_cstructhex=to_helper~empty_return:empty_cstruct~create:Cstruct.create~set:Cstruct.set_charhexletof_bigstring?(ignore=[])buf=of_helper~ignore(Bigarray.Array1.getbuf)(Bigarray.Array1.dimbuf)letto_bigstringhex=to_helper~empty_return:empty_cstruct.buffer~create:Bigarray.(Array1.createcharc_layout)~set:Bigarray.Array1.sethexlethexdump_s?(print_row_numbers=true)?(print_chars=true)(`Hexs)=letchar_len=16in(* row width in # chars *)lethex_len=char_len*2in(* row width in # hex chars *)(* Buf length is roughly 4... could put this in exactly but very brittle *)letbuf=Buffer.create((String.lengths)*4)inlet(<=)bufs=Buffer.add_stringbufsin(* Create three columns -- row #, hex and ascii chars*)letn=String.lengthsinletrows=(n/hex_len)+(ifnmodhex_len=0then0else1)inforrow=0torows-1doletlast_row=row=rows-1in(* First column is row number *)ifprint_row_numbersthenbuf<=Printf.sprintf"%.8d: "row;(* Row length is hex_length, unless we are on the last row and we
have less than hex_length left *)letrow_len=iflast_rowthen(letrem=nmodhex_leninifrem=0thenhex_lenelserem)elsehex_leninfori=0torow_len-1do(* Second column is the hex *)ifimod4=0&&i<>0thenbuf<=Printf.sprintf" ";leti=i+(row*hex_len)inbuf<=Printf.sprintf"%c"(String.getsi)done;(* This is only needed for the last row -- pad if less than len *)iflast_rowthenletmissed_chars=hex_len-row_leninletpad=missed_charsin(* Every four chars add spacing *)letpad=pad+(missed_chars/4)inbuf<=Printf.sprintf"%s"(String.makepad' ')else();(* Third column is ascii *)ifprint_charsthenbeginbuf<=" ";letrecauxij=ifi>row_len-2then()elsebeginletpos=i+(row*hex_len)inletpos'=pos+1inletc=to_char(String.getspos)(String.getspos')inifchar_is_printablecthenbuf<=Printf.sprintf"%c"celsebuf<=".";aux(j+1)(j+2)endinaux01;end;buf<="\n";done;Buffer.contentsbuflethexdump?print_row_numbers?print_charshex=Printf.printf"%s"(hexdump_s?print_row_numbers?print_charshex)letppppf(`Hexhex)=Format.pp_print_stringppfhexletshow(`Hexhex)=hex