This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,4 @@
_build/
.merlin
*.install
.*.swp

View file

@ -0,0 +1,72 @@
v1.5.0 2022-04-07
-----------------
* Only print printable ASCII characters (#17 @copy)
* Improve error message with odd number of characters (#35 @dialohq)
* Raise lower bound to OCaml 4.08 (#37 @hannesm)
* Remove bigarray-compat dependency (#37 @hannesm)
* Remove "build" from dune dependency (#34 @CraigFE)
* Improve documentation of `of_string` (#37 @hannesm, fixes #33 #36)
v1.4.0 2019-03-28
-----------------
* Drop the hard dependency on `unix` that is transitively
brought in by cstruct/bigarray. This is done by using
the new `bigarray-compat` opam package that does the
right thing on OCaml 4.07+ to not depend on unix.
On older OCaml compilers the dependency will still be
there and must be manually dropped with `-dontlink`, but
we encourage users to use a newer compiler (#29 @TheLortex)
v1.3.0 2019-02-01
-----------------
* Add `to/of_bytes/bigstring` functions. (#27 @vbmithr)
* Install toplevel printers automatically in modern utop (@avsm)
* Port from jbuilder to dune (@avsm)
* Use `dune-release` instead of topkg (@avsm)
* Update opam metadata to 2.0 format (@avsm)
* Improve ocamldoc (@avsm)
v1.2.0 2017-11-05
-----------------
* Fix build with OCaml 4.06 (and -safe-string) (#25 @djs55)
* Add pretty-printers (#23 @vbmithr)
* Make jbuilder a build dependency (#22 @samoht)
v1.1.1 2017-05-26
-----------------
* Add topkg-jbuilder support.
v1.1.0 2017-05-23
-----------------
* Port build to [Jbuilder](https://github.com/janestreet/jbuilder) (#19 @avsm).
* Modernise Travis CI test matrix (#19 @avsm).
* Add `LICENSE` file (#18 @djs55).
v1.0.0 2015-10-13
-----------------
* Fix performance issues: make `of_string` less consy when `ignore` is empty
(#13, fix by @yallop)
* Add missing `Bytes` dependency (#16)
v0.2.0 2015-05-04
------------------
* Add an `opam` file
* Add Travis CI files
* Add `Hex.of_cstruct` and `Hex.to_cstruct` to converters from and to cstructs
(#5 by @trevorsummerssmith)
* Add `Hex.hexdump` to pretty-print an hex value (#6 by @trevorsummerssmith)
* Change the optional argument of `Hex.of_string` to take a list of characters
to ignore (#6 by @trevorsummerssmith)
v0.1.0 2014-09-24
-----------------
* Initial release

View file

@ -0,0 +1,16 @@
(*
* 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.
*)

View file

@ -0,0 +1,20 @@
.PHONY: build clean test install uninstall doc
build:
dune build
test:
dune runtest
install:
dune install
uninstall:
dune uninstall
doc:
dune build @doc
clean:
rm -rf _build *.install

View file

@ -0,0 +1,15 @@
### ocaml-hex -- a minimal library providing hexadecimal converters
[![Build Status](https://travis-ci.org/mirage/ocaml-hex.svg)](https://travis-ci.org/mirage/ocaml-hex)
[![docs](https://img.shields.io/badge/doc-online-blue.svg)](http://docs.mirage.io/hex/)
```ocaml
# #require "hex";;
# Hex.of_string "Hello world!";;
- : Hex.t = `Hex "48656c6c6f20776f726c6421"
# Hex.to_string (`Hex "deadbeef");;
- : string = "Þ­¾ï"
# Hex.hexdump (Hex.of_string "Hello world!\n")
00000000: 4865 6c6c 6f20 776f 726c 6421 0a Hello world!.
- : unit = ()
```

View file

@ -0,0 +1,3 @@
(lang dune 1.0)
(name hex)
(version v1.5.0)

View file

@ -0,0 +1,32 @@
version: "1.5.0"
opam-version: "2.0"
maintainer: "thomas@gazagnaire.org"
authors: ["Thomas Gazagnaire" "Trevor Summers Smith"]
license: "ISC"
homepage: "https://github.com/mirage/ocaml-hex"
doc: "https://mirage.github.io/ocaml-hex/"
bug-reports: "https://github.com/mirage/ocaml-hex/issues"
depends: [
"ocaml" {>="4.08.0"}
"dune" {>= "1.0"}
"cstruct" {>= "1.7.0"}
]
build: [
["dune" "subst"] {dev}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
dev-repo: "git+https://github.com/mirage/ocaml-hex.git"
synopsis: "Library providing hexadecimal converters"
description: """
```ocaml
#require "hex";;
# Hex.of_string "Hello world!";;
- : Hex.t = "48656c6c6f20776f726c6421"
# Hex.to_string "dead-beef";;
- : string = "ޭ<><DEAD>"
# Hex.hexdump (Hex.of_string "Hello world!\n")
00000000: 4865 6c6c 6f20 776f 726c 6421 0a Hello world!.
- : unit = ()
```
"""

View file

@ -0,0 +1,4 @@
(library
(name hex)
(public_name hex)
(libraries cstruct))

View file

@ -0,0 +1,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

View file

@ -0,0 +1,114 @@
(*
* 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.
*)
(** Hexadecimal encoding.
[Hex] defines hexadecimal encodings for {{!char}characters},
{{!string}strings} and {{!cstruct}Cstruct.t} buffers. *)
type t = [`Hex of string]
(** The type var hexadecimal values. *)
(** {1:char Characters} *)
val of_char: char -> char * char
(** [of_char c] is the the hexadecimal encoding of the character
[c]. *)
val to_char: char -> char -> char
(** [to_char x y] is the character correspondong to the [xy]
hexadecimal encoding. *)
(** {1:string Strings} *)
val of_string: ?ignore:char list -> string -> t
(** [of_string s] is the hexadecimal representation of the binary
string [s]. If [ignore] is set, skip the characters in the list
when converting. E.g. [of_string ~ignore:[' '] "Mirage OS"] is
[`Hex "4d69726167654f53"], [of_string "Mirage OS"] is
[`Hex "4d6972616765204f53"] (with a "20" before the "OS" ("4f53")).
The default value of [ignore] is [[]]).
If you have a hex string as input (i.e. "4f53"), you can use
[to_string (`Hex "4f53")] to decode it to a binary string ("OS"). *)
val to_string: t -> string
(** [to_string t] is the binary string [s] such that [of_string s] is
[t]. *)
(** {1:byte Bytes} *)
val of_bytes: ?ignore:char list -> bytes -> t
(** [of_bytes s] is the hexadecimal representation of the binary
string [s]. If [ignore] is set, skip the characters in the list
when converting. Eg [of_bytes ~ignore:[' '] "a f"]. The default
value of [ignore] is [[]]). *)
val to_bytes: t -> bytes
(** [to_bytes t] is the binary string [s] such that [of_bytes s] is
[t]. *)
(** {1:cstruct Cstruct} *)
val of_cstruct: ?ignore:char list -> Cstruct.t -> t
(** [of_cstruct buf] is the hexadecimal representation of the buffer
[buf]. *)
val to_cstruct: t -> Cstruct.t
(** [to_cstruct t] is the buffer [b] such that [of_cstruct b] is
[t]. *)
(** {1:Bigstring Bigstring} *)
val of_bigstring: ?ignore:char list -> Cstruct.buffer -> t
(** [of_bigstring buf] is the hexadecimal representation of the buffer
[buf]. *)
val to_bigstring: t -> Cstruct.buffer
(** [to_bigstring t] is the buffer [b] such that [of_bigstring b] is
[t]. *)
(** {1 Debugging} *)
val hexdump: ?print_row_numbers:bool -> ?print_chars:bool -> t -> unit
(** [hexdump h] dumps the hex encoding to stdout in the following format:
{v
00000000: 6865 6c6c 6f20 776f 726c 6420 6865 6c6c hello world hell
00000010: 6f20 776f 726c 640a o world.
v}
This is the same format as emacs hexl-mode, and is a very similar
format to hexdump -C. '\t' and '\n' are printed as '.'.in the char
column.
[print_row_numbers] and [print_chars] both default to
[true]. Setting either to [false] does not print the column.
*)
val hexdump_s: ?print_row_numbers:bool -> ?print_chars:bool -> t -> string
(** Same as [hexdump] except returns a string. *)
(** {1 Pretty printing} *)
val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
(** [pp fmt t] will output a human-readable hex representation of [t]
to the formatter [fmt]. *)
val show : t -> string
(** [show t] will return a human-readable hex representation of [t] as
a string. *)

View file

@ -0,0 +1,3 @@
(test
(name test)
(libraries hex))

View file

@ -0,0 +1,94 @@
let () = Random.self_init ()
let random_string () =
let s = Bytes.create (Random.int 20483) in
for i = 0 to Bytes.length s - 1 do
Bytes.set s i (Char.chr (Random.int 256))
done;
Bytes.to_string s
let check msg x y =
if x = y then ()
else (
Printf.eprintf "\n---\n%S\n---\n%S\n%s: \027[31mERROR!\027[m\n" x y msg;
exit 1
)
let success = ref 0
let test s =
let h1 = Hex.of_string s in
check "to/from string" s (Hex.to_string h1);
incr success
let test_cs s =
let cs = Cstruct.of_string s in
let `Hex s = Hex.of_cstruct cs in
let `Hex s' = (Hex.of_string (Cstruct.to_string cs)) in
check "of_cstruct = of_string" s s';
incr success
let test_suite test =
test "";
test "deadbeef";
for _ = 0 to 100 do
test (random_string ())
done
let test_cs_array () =
let open Bigarray in
let arr = Array1.of_array char c_layout
[|'0'; '1'; '2'; '3'; '4'; '5';
'6'; '7'; '8'; '9'; 'a'; 'b';
'c'; 'd'; 'e'; 'f'|] in
let cs = Cstruct.of_bigarray arr in
let hex = Hex.of_cstruct cs in
let s = Hex.to_string hex in
check "cstruct array" s "0123456789abcdef";
incr success
let test_ignore () =
let s = "... aJjf...c 1" in
let h = Hex.of_string ~ignore:[' '; '.'; 'j'; 'J'] s in
check "string ignore" "afc1" (Hex.to_string h);
let cs = Cstruct.of_string s in
let h = Hex.of_cstruct ~ignore:[' '; '.'; 'j'; 'J'] cs in
check "cstruct ignore" "afc1" (Cstruct.to_string (Hex.to_cstruct h))
let test_hexdump () =
let test input answer =
let hex = Hex.of_string input in
let s = Hex.hexdump_s hex in
check "hexdump" s answer
in
(* unprintable *)
test "\x00\x01\x09\x10\x1f\x80\xff" "00000000: 0001 0910 1f80 ff .......\n";
(* Test out the various padding situations we need to get right *)
(* Less than 1 row *)
test "i am less" "00000000: 6920 616d 206c 6573 73 i am less\n";
(* Exactly 2 rows long *)
test "i am a 32 character string......" "00000000: 6920 616d 2061 2033 3220 6368 6172 6163 i am a 32 charac\n00000001: 7465 7220 7374 7269 6e67 2e2e 2e2e 2e2e ter string......\n";
(* 8 rows with some remainder *)
let input = "# OASIS_START
# DO NOT EDIT (digest: 3a6a404057e98b471c7d0eb9f9ea243c)
version = \"0.1.0\"
description = \"Hexadecimal converter\"" in
let hex = Hex.of_string input in
let s = Hex.hexdump_s hex in
check "hexdump" s "00000000: 2320 4f41 5349 535f 5354 4152 540a 2320 # OASIS_START.#
00000001: 444f 204e 4f54 2045 4449 5420 2864 6967 DO NOT EDIT (dig
00000002: 6573 743a 2033 6136 6134 3034 3035 3765 est: 3a6a404057e
00000003: 3938 6234 3731 6337 6430 6562 3966 3965 98b471c7d0eb9f9e
00000004: 6132 3433 6329 0a76 6572 7369 6f6e 203d a243c).version =
00000005: 2022 302e 312e 3022 0a64 6573 6372 6970 \"0.1.0\".descrip
00000006: 7469 6f6e 203d 2022 4865 7861 6465 6369 tion = \"Hexadeci
00000007: 6d61 6c20 636f 6e76 6572 7465 7222 mal converter\"\n";
incr success
let () =
test_suite test;
test_suite test_cs;
test_cs_array ();
test_ignore ();
test_hexdump ();
Printf.printf "\027[32mSUCCESS!\027[m (%d/%d tests pass)\n" !success !success