├── .gitignore ├── CHANGES.md ├── LICENSE.md ├── Makefile ├── README.md ├── dune-project ├── hex.opam ├── lib ├── dune ├── hex.ml └── hex.mli └── lib_test ├── dune └── test.ml /.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | .merlin 3 | *.install 4 | .*.swp 5 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | v1.5.0 2022-04-07 2 | ----------------- 3 | 4 | * Only print printable ASCII characters (#17 @copy) 5 | * Improve error message with odd number of characters (#35 @dialohq) 6 | * Raise lower bound to OCaml 4.08 (#37 @hannesm) 7 | * Remove bigarray-compat dependency (#37 @hannesm) 8 | * Remove "build" from dune dependency (#34 @CraigFE) 9 | * Improve documentation of `of_string` (#37 @hannesm, fixes #33 #36) 10 | 11 | v1.4.0 2019-03-28 12 | ----------------- 13 | 14 | * Drop the hard dependency on `unix` that is transitively 15 | brought in by cstruct/bigarray. This is done by using 16 | the new `bigarray-compat` opam package that does the 17 | right thing on OCaml 4.07+ to not depend on unix. 18 | On older OCaml compilers the dependency will still be 19 | there and must be manually dropped with `-dontlink`, but 20 | we encourage users to use a newer compiler (#29 @TheLortex) 21 | 22 | v1.3.0 2019-02-01 23 | ----------------- 24 | 25 | * Add `to/of_bytes/bigstring` functions. (#27 @vbmithr) 26 | * Install toplevel printers automatically in modern utop (@avsm) 27 | * Port from jbuilder to dune (@avsm) 28 | * Use `dune-release` instead of topkg (@avsm) 29 | * Update opam metadata to 2.0 format (@avsm) 30 | * Improve ocamldoc (@avsm) 31 | 32 | v1.2.0 2017-11-05 33 | ----------------- 34 | 35 | * Fix build with OCaml 4.06 (and -safe-string) (#25 @djs55) 36 | * Add pretty-printers (#23 @vbmithr) 37 | * Make jbuilder a build dependency (#22 @samoht) 38 | 39 | v1.1.1 2017-05-26 40 | ----------------- 41 | 42 | * Add topkg-jbuilder support. 43 | 44 | v1.1.0 2017-05-23 45 | ----------------- 46 | 47 | * Port build to [Jbuilder](https://github.com/janestreet/jbuilder) (#19 @avsm). 48 | * Modernise Travis CI test matrix (#19 @avsm). 49 | * Add `LICENSE` file (#18 @djs55). 50 | 51 | v1.0.0 2015-10-13 52 | ----------------- 53 | 54 | * Fix performance issues: make `of_string` less consy when `ignore` is empty 55 | (#13, fix by @yallop) 56 | * Add missing `Bytes` dependency (#16) 57 | 58 | v0.2.0 2015-05-04 59 | ------------------ 60 | 61 | * Add an `opam` file 62 | * Add Travis CI files 63 | * Add `Hex.of_cstruct` and `Hex.to_cstruct` to converters from and to cstructs 64 | (#5 by @trevorsummerssmith) 65 | * Add `Hex.hexdump` to pretty-print an hex value (#6 by @trevorsummerssmith) 66 | * Change the optional argument of `Hex.of_string` to take a list of characters 67 | to ignore (#6 by @trevorsummerssmith) 68 | 69 | v0.1.0 2014-09-24 70 | ----------------- 71 | 72 | * Initial release 73 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2015 Trevor Summers Smith 3 | * Copyright (c) 2014 Thomas Gazagnaire 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | *) 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: build clean test install uninstall doc 3 | 4 | build: 5 | dune build 6 | 7 | test: 8 | dune runtest 9 | 10 | install: 11 | dune install 12 | 13 | uninstall: 14 | dune uninstall 15 | 16 | doc: 17 | dune build @doc 18 | 19 | clean: 20 | rm -rf _build *.install 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirage/ocaml-hex/6c9aa112af0d158c7e652c6efd4dc1a9bc5fb790/README.md -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 1.0) 2 | (name hex) 3 | -------------------------------------------------------------------------------- /hex.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "thomas@gazagnaire.org" 3 | authors: ["Thomas Gazagnaire" "Trevor Summers Smith"] 4 | license: "ISC" 5 | homepage: "https://github.com/mirage/ocaml-hex" 6 | doc: "https://mirage.github.io/ocaml-hex/" 7 | bug-reports: "https://github.com/mirage/ocaml-hex/issues" 8 | depends: [ 9 | "ocaml" {>="4.08.0"} 10 | "dune" {>= "1.0"} 11 | "cstruct" {>= "1.7.0"} 12 | ] 13 | build: [ 14 | ["dune" "subst"] {dev} 15 | ["dune" "build" "-p" name "-j" jobs] 16 | ["dune" "runtest" "-p" name "-j" jobs] {with-test} 17 | ] 18 | dev-repo: "git+https://github.com/mirage/ocaml-hex.git" 19 | synopsis: "Library providing hexadecimal converters" 20 | description: """ 21 | ```ocaml 22 | #require "hex";; 23 | # Hex.of_string "Hello world!";; 24 | - : Hex.t = "48656c6c6f20776f726c6421" 25 | # Hex.to_string "dead-beef";; 26 | - : string = "ޭ��" 27 | # Hex.hexdump (Hex.of_string "Hello world!\n") 28 | 00000000: 4865 6c6c 6f20 776f 726c 6421 0a Hello world!. 29 | - : unit = () 30 | ``` 31 | """ 32 | x-maintenance-intent: [ "(latest)" ] 33 | -------------------------------------------------------------------------------- /lib/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name hex) 3 | (public_name hex) 4 | (libraries cstruct)) 5 | -------------------------------------------------------------------------------- /lib/hex.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2015 Trevor Summers Smith 3 | * Copyright (c) 2014 Thomas Gazagnaire 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | *) 17 | 18 | type t = [`Hex of string] 19 | 20 | let invalid_arg fmt = 21 | Printf.ksprintf (fun str -> raise (Invalid_argument str)) fmt 22 | 23 | let hexa = "0123456789abcdef" 24 | and hexa1 = 25 | "0000000000000000111111111111111122222222222222223333333333333333\ 26 | 4444444444444444555555555555555566666666666666667777777777777777\ 27 | 88888888888888889999999999999999aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb\ 28 | ccccccccccccccccddddddddddddddddeeeeeeeeeeeeeeeeffffffffffffffff" 29 | and hexa2 = 30 | "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\ 31 | 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\ 32 | 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\ 33 | 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" 34 | 35 | let char_is_printable chr = 36 | chr >= ' ' && chr <= '~' 37 | 38 | let of_char c = 39 | let x = Char.code c in 40 | hexa.[x lsr 4], hexa.[x land 0xf] 41 | 42 | let to_char x y = 43 | let code c = match c with 44 | | '0'..'9' -> Char.code c - 48 (* Char.code '0' *) 45 | | 'A'..'F' -> Char.code c - 55 (* Char.code 'A' + 10 *) 46 | | 'a'..'f' -> Char.code c - 87 (* Char.code 'a' + 10 *) 47 | | _ -> invalid_arg "Hex.to_char: %d is an invalid char" (Char.code c) 48 | in 49 | Char.chr (code x lsl 4 + code y) 50 | 51 | let of_string_fast s = 52 | let len = String.length s in 53 | let buf = Bytes.create (len * 2) in 54 | for i = 0 to len - 1 do 55 | Bytes.unsafe_set buf (i * 2) 56 | (String.unsafe_get hexa1 (Char.code (String.unsafe_get s i))); 57 | Bytes.unsafe_set buf (succ (i * 2)) 58 | (String.unsafe_get hexa2 (Char.code (String.unsafe_get s i))); 59 | done; 60 | `Hex (Bytes.to_string buf) 61 | 62 | let of_helper ~ignore (next : int -> char) len = 63 | let buf = Buffer.create len in 64 | for i = 0 to len - 1 do 65 | let c = next i in 66 | if List.mem c ignore then () 67 | else 68 | let x,y = of_char c in 69 | Buffer.add_char buf x; 70 | Buffer.add_char buf y; 71 | done; 72 | `Hex (Buffer.contents buf) 73 | 74 | let of_string ?(ignore = []) s = 75 | match ignore with 76 | | [] -> of_string_fast s 77 | | ignore -> of_helper ~ignore (fun i -> s.[i]) (String.length s) 78 | 79 | let of_bytes ?ignore b = 80 | of_string ?ignore (Bytes.to_string b) 81 | 82 | let to_helper ~empty_return ~create ~set (`Hex s) = 83 | if s = "" then empty_return 84 | else 85 | let n = String.length s in 86 | let buf = create (n/2) in 87 | let rec aux i j = 88 | if i >= n then () 89 | else if j >= n then invalid_arg "Hex conversion: Hex string cannot have an odd number of characters." 90 | else ( 91 | set buf (i/2) (to_char s.[i] s.[j]); 92 | aux (j+1) (j+2) 93 | ) 94 | in 95 | aux 0 1; 96 | buf 97 | 98 | let to_bytes hex = 99 | to_helper ~empty_return:Bytes.empty ~create:Bytes.create ~set:Bytes.set hex 100 | 101 | let to_string hex = Bytes.to_string @@ to_bytes hex 102 | 103 | let of_cstruct ?(ignore=[]) cs = 104 | let open Cstruct in 105 | of_helper 106 | ~ignore 107 | (fun i -> Bigarray.Array1.get cs.buffer (cs.off+i)) 108 | cs.len 109 | 110 | (* Allocate just once for to_cstruct *) 111 | let empty_cstruct = Cstruct.of_string "" 112 | 113 | let to_cstruct hex = 114 | to_helper 115 | ~empty_return:empty_cstruct ~create:Cstruct.create ~set:Cstruct.set_char hex 116 | 117 | let of_bigstring ?(ignore=[]) buf = 118 | of_helper 119 | ~ignore 120 | (Bigarray.Array1.get buf) 121 | (Bigarray.Array1.dim buf) 122 | 123 | let to_bigstring hex = 124 | to_helper 125 | ~empty_return:empty_cstruct.buffer 126 | ~create:Bigarray.(Array1.create char c_layout) 127 | ~set:Bigarray.Array1.set hex 128 | 129 | let hexdump_s ?(print_row_numbers=true) ?(print_chars=true) (`Hex s) = 130 | let char_len = 16 in (* row width in # chars *) 131 | let hex_len = char_len * 2 in (* row width in # hex chars *) 132 | (* Buf length is roughly 4... could put this in exactly but very brittle *) 133 | let buf = Buffer.create ((String.length s) * 4) in 134 | let ( <= ) buf s = Buffer.add_string buf s in 135 | (* Create three columns -- row #, hex and ascii chars*) 136 | let n = String.length s in 137 | let rows = (n / hex_len) + (if n mod hex_len = 0 then 0 else 1) in 138 | for row = 0 to rows-1 do 139 | let last_row = row = rows-1 in 140 | (* First column is row number *) 141 | if print_row_numbers then 142 | buf <= Printf.sprintf "%.8d: " row; 143 | (* Row length is hex_length, unless we are on the last row and we 144 | have less than hex_length left *) 145 | let row_len = if last_row then 146 | (let rem = n mod hex_len in 147 | if rem = 0 then hex_len else rem) 148 | else hex_len in 149 | for i = 0 to row_len-1 do 150 | (* Second column is the hex *) 151 | if i mod 4 = 0 && i <> 0 then buf <= Printf.sprintf " "; 152 | let i = i + (row * hex_len) in 153 | buf <= Printf.sprintf "%c" (String.get s i) 154 | done; 155 | (* This is only needed for the last row -- pad if less than len *) 156 | if last_row then 157 | let missed_chars = hex_len - row_len in 158 | let pad = missed_chars in 159 | (* Every four chars add spacing *) 160 | let pad = pad + (missed_chars / 4) in 161 | buf <= Printf.sprintf "%s" (String.make pad ' ') 162 | else (); 163 | (* Third column is ascii *) 164 | if print_chars then begin 165 | buf <= " "; 166 | let rec aux i j = 167 | if i > row_len - 2 then () 168 | else begin 169 | let pos = i + (row * hex_len) in 170 | let pos' = pos + 1 in 171 | let c = to_char (String.get s pos) (String.get s pos') in 172 | if char_is_printable c then 173 | buf <= Printf.sprintf "%c" c 174 | else 175 | buf <= "."; 176 | aux (j+1) (j+2) 177 | end 178 | in 179 | aux 0 1; 180 | end; 181 | buf <= "\n"; 182 | done; 183 | Buffer.contents buf 184 | 185 | let hexdump ?print_row_numbers ?print_chars hex = 186 | Printf.printf "%s" (hexdump_s ?print_row_numbers ?print_chars hex) 187 | 188 | let pp ppf (`Hex hex) = 189 | Format.pp_print_string ppf hex 190 | 191 | let show (`Hex hex) = hex 192 | -------------------------------------------------------------------------------- /lib/hex.mli: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2015 Trevor Summers Smith 3 | * Copyright (c) 2014 Thomas Gazagnaire 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | *) 17 | 18 | (** Hexadecimal encoding. 19 | 20 | [Hex] defines hexadecimal encodings for {{!char}characters}, 21 | {{!string}strings} and {{!cstruct}Cstruct.t} buffers. *) 22 | 23 | type t = [`Hex of string] 24 | (** The type var hexadecimal values. *) 25 | 26 | (** {1:char Characters} *) 27 | 28 | val of_char: char -> char * char 29 | (** [of_char c] is the the hexadecimal encoding of the character 30 | [c]. *) 31 | 32 | val to_char: char -> char -> char 33 | (** [to_char x y] is the character correspondong to the [xy] 34 | hexadecimal encoding. *) 35 | 36 | (** {1:string Strings} *) 37 | 38 | val of_string: ?ignore:char list -> string -> t 39 | (** [of_string s] is the hexadecimal representation of the binary 40 | string [s]. If [ignore] is set, skip the characters in the list 41 | when converting. E.g. [of_string ~ignore:[' '] "Mirage OS"] is 42 | [`Hex "4d69726167654f53"], [of_string "Mirage OS"] is 43 | [`Hex "4d6972616765204f53"] (with a "20" before the "OS" ("4f53")). 44 | The default value of [ignore] is [[]]). 45 | 46 | If you have a hex string as input (i.e. "4f53"), you can use 47 | [to_string (`Hex "4f53")] to decode it to a binary string ("OS"). *) 48 | 49 | val to_string: t -> string 50 | (** [to_string t] is the binary string [s] such that [of_string s] is 51 | [t]. *) 52 | 53 | (** {1:byte Bytes} *) 54 | 55 | val of_bytes: ?ignore:char list -> bytes -> t 56 | (** [of_bytes s] is the hexadecimal representation of the binary 57 | string [s]. If [ignore] is set, skip the characters in the list 58 | when converting. Eg [of_bytes ~ignore:[' '] "a f"]. The default 59 | value of [ignore] is [[]]). *) 60 | 61 | val to_bytes: t -> bytes 62 | (** [to_bytes t] is the binary string [s] such that [of_bytes s] is 63 | [t]. *) 64 | 65 | (** {1:cstruct Cstruct} *) 66 | 67 | val of_cstruct: ?ignore:char list -> Cstruct.t -> t 68 | (** [of_cstruct buf] is the hexadecimal representation of the buffer 69 | [buf]. *) 70 | 71 | val to_cstruct: t -> Cstruct.t 72 | (** [to_cstruct t] is the buffer [b] such that [of_cstruct b] is 73 | [t]. *) 74 | 75 | (** {1:Bigstring Bigstring} *) 76 | 77 | val of_bigstring: ?ignore:char list -> Cstruct.buffer -> t 78 | (** [of_bigstring buf] is the hexadecimal representation of the buffer 79 | [buf]. *) 80 | 81 | val to_bigstring: t -> Cstruct.buffer 82 | (** [to_bigstring t] is the buffer [b] such that [of_bigstring b] is 83 | [t]. *) 84 | 85 | (** {1 Debugging} *) 86 | 87 | val hexdump: ?print_row_numbers:bool -> ?print_chars:bool -> t -> unit 88 | (** [hexdump h] dumps the hex encoding to stdout in the following format: 89 | 90 | {v 91 | 00000000: 6865 6c6c 6f20 776f 726c 6420 6865 6c6c hello world hell 92 | 00000010: 6f20 776f 726c 640a o world. 93 | v} 94 | 95 | This is the same format as emacs hexl-mode, and is a very similar 96 | format to hexdump -C. '\t' and '\n' are printed as '.'.in the char 97 | column. 98 | 99 | [print_row_numbers] and [print_chars] both default to 100 | [true]. Setting either to [false] does not print the column. 101 | *) 102 | 103 | val hexdump_s: ?print_row_numbers:bool -> ?print_chars:bool -> t -> string 104 | (** Same as [hexdump] except returns a string. *) 105 | 106 | (** {1 Pretty printing} *) 107 | 108 | val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer] 109 | (** [pp fmt t] will output a human-readable hex representation of [t] 110 | to the formatter [fmt]. *) 111 | 112 | val show : t -> string 113 | (** [show t] will return a human-readable hex representation of [t] as 114 | a string. *) 115 | -------------------------------------------------------------------------------- /lib_test/dune: -------------------------------------------------------------------------------- 1 | (test 2 | (name test) 3 | (libraries hex)) 4 | -------------------------------------------------------------------------------- /lib_test/test.ml: -------------------------------------------------------------------------------- 1 | let () = Random.self_init () 2 | 3 | let random_string () = 4 | let s = Bytes.create (Random.int 20483) in 5 | for i = 0 to Bytes.length s - 1 do 6 | Bytes.set s i (Char.chr (Random.int 256)) 7 | done; 8 | Bytes.to_string s 9 | 10 | let check msg x y = 11 | if x = y then () 12 | else ( 13 | Printf.eprintf "\n---\n%S\n---\n%S\n%s: \027[31mERROR!\027[m\n" x y msg; 14 | exit 1 15 | ) 16 | 17 | let success = ref 0 18 | 19 | let test s = 20 | let h1 = Hex.of_string s in 21 | check "to/from string" s (Hex.to_string h1); 22 | incr success 23 | 24 | let test_cs s = 25 | let cs = Cstruct.of_string s in 26 | let `Hex s = Hex.of_cstruct cs in 27 | let `Hex s' = (Hex.of_string (Cstruct.to_string cs)) in 28 | check "of_cstruct = of_string" s s'; 29 | incr success 30 | 31 | let test_suite test = 32 | test ""; 33 | test "deadbeef"; 34 | for _ = 0 to 100 do 35 | test (random_string ()) 36 | done 37 | 38 | let test_cs_array () = 39 | let open Bigarray in 40 | let arr = Array1.of_array char c_layout 41 | [|'0'; '1'; '2'; '3'; '4'; '5'; 42 | '6'; '7'; '8'; '9'; 'a'; 'b'; 43 | 'c'; 'd'; 'e'; 'f'|] in 44 | let cs = Cstruct.of_bigarray arr in 45 | let hex = Hex.of_cstruct cs in 46 | let s = Hex.to_string hex in 47 | check "cstruct array" s "0123456789abcdef"; 48 | incr success 49 | 50 | let test_ignore () = 51 | let s = "... aJjf...c 1" in 52 | let h = Hex.of_string ~ignore:[' '; '.'; 'j'; 'J'] s in 53 | check "string ignore" "afc1" (Hex.to_string h); 54 | let cs = Cstruct.of_string s in 55 | let h = Hex.of_cstruct ~ignore:[' '; '.'; 'j'; 'J'] cs in 56 | check "cstruct ignore" "afc1" (Cstruct.to_string (Hex.to_cstruct h)) 57 | 58 | let test_hexdump () = 59 | let test input answer = 60 | let hex = Hex.of_string input in 61 | let s = Hex.hexdump_s hex in 62 | check "hexdump" s answer 63 | in 64 | (* unprintable *) 65 | test "\x00\x01\x09\x10\x1f\x80\xff" "00000000: 0001 0910 1f80 ff .......\n"; 66 | (* Test out the various padding situations we need to get right *) 67 | (* Less than 1 row *) 68 | test "i am less" "00000000: 6920 616d 206c 6573 73 i am less\n"; 69 | (* Exactly 2 rows long *) 70 | 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"; 71 | (* 8 rows with some remainder *) 72 | let input = "# OASIS_START 73 | # DO NOT EDIT (digest: 3a6a404057e98b471c7d0eb9f9ea243c) 74 | version = \"0.1.0\" 75 | description = \"Hexadecimal converter\"" in 76 | let hex = Hex.of_string input in 77 | let s = Hex.hexdump_s hex in 78 | check "hexdump" s "00000000: 2320 4f41 5349 535f 5354 4152 540a 2320 # OASIS_START.# 79 | 00000001: 444f 204e 4f54 2045 4449 5420 2864 6967 DO NOT EDIT (dig 80 | 00000002: 6573 743a 2033 6136 6134 3034 3035 3765 est: 3a6a404057e 81 | 00000003: 3938 6234 3731 6337 6430 6562 3966 3965 98b471c7d0eb9f9e 82 | 00000004: 6132 3433 6329 0a76 6572 7369 6f6e 203d a243c).version = 83 | 00000005: 2022 302e 312e 3022 0a64 6573 6372 6970 \"0.1.0\".descrip 84 | 00000006: 7469 6f6e 203d 2022 4865 7861 6465 6369 tion = \"Hexadeci 85 | 00000007: 6d61 6c20 636f 6e76 6572 7465 7222 mal converter\"\n"; 86 | incr success 87 | 88 | let () = 89 | test_suite test; 90 | test_suite test_cs; 91 | test_cs_array (); 92 | test_ignore (); 93 | test_hexdump (); 94 | Printf.printf "\027[32mSUCCESS!\027[m (%d/%d tests pass)\n" !success !success 95 | --------------------------------------------------------------------------------