Compare commits
No commits in common. "main" and "gh-pages" have entirely different histories.
49 changed files with 2130 additions and 352 deletions
|
@ -1,8 +0,0 @@
|
|||
## v0.2.0 (2024-03-18)
|
||||
|
||||
* Rename pp to pp_hexdump
|
||||
* Add a pp which just prints the hex with some spaces, but no newlines
|
||||
|
||||
## v0.1.0 (2024-03-14)
|
||||
|
||||
* Initial release
|
23
LICENSE.md
23
LICENSE.md
|
@ -1,23 +0,0 @@
|
|||
Copyright (c) 2024, Hannes Mehnert
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
0
README
Normal file
0
README
Normal file
10
README.md
10
README.md
|
@ -1,10 +0,0 @@
|
|||
## oHEX
|
||||
|
||||
This package with minimal dependency cone provides functionality to decode and
|
||||
encode strings into hexadecimal representation.
|
||||
|
||||
As example, `Ohex.decode "4142" = "AB"`. And `Ohex.encode "AB" = "4142"`.
|
||||
|
||||
There's even the property, for all strings s: `Ohex.(decode (encode s)) = s`.
|
||||
|
||||
A pretty-printer is provided as well.
|
19
doc/index.html
Normal file
19
doc/index.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>index</title>
|
||||
<link rel="stylesheet" href="./odoc.support/odoc.css"/>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
||||
</head>
|
||||
<body>
|
||||
<main class="content">
|
||||
<div class="by-name">
|
||||
<h2>OCaml package documentation</h2>
|
||||
<ol>
|
||||
<li><a href="ohex/index.html">ohex</a> <span class="version">0.2.0</span></li>
|
||||
</ol>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
BIN
doc/odoc.support/fonts/KaTeX_AMS-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_AMS-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Caligraphic-Bold.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Caligraphic-Bold.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Caligraphic-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Caligraphic-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Fraktur-Bold.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Fraktur-Bold.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Fraktur-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Fraktur-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Main-Bold.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Main-Bold.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Main-BoldItalic.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Main-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Main-Italic.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Main-Italic.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Main-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Main-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Math-BoldItalic.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Math-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Math-Italic.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Math-Italic.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_SansSerif-Bold.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_SansSerif-Bold.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_SansSerif-Italic.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_SansSerif-Italic.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_SansSerif-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_SansSerif-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Script-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Script-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Size1-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Size1-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Size2-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Size2-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Size3-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Size3-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Size4-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Size4-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/KaTeX_Typewriter-Regular.woff2
Normal file
BIN
doc/odoc.support/fonts/KaTeX_Typewriter-Regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/fira-mono-v14-latin-500.woff2
Normal file
BIN
doc/odoc.support/fonts/fira-mono-v14-latin-500.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/fira-mono-v14-latin-regular.woff2
Normal file
BIN
doc/odoc.support/fonts/fira-mono-v14-latin-regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-500.woff2
Normal file
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-500.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-500italic.woff2
Normal file
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-500italic.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-700.woff2
Normal file
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-700.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-700italic.woff2
Normal file
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-700italic.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-italic.woff2
Normal file
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-italic.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-regular.woff2
Normal file
BIN
doc/odoc.support/fonts/fira-sans-v17-latin-regular.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/noticia-text-v15-latin-700.woff2
Normal file
BIN
doc/odoc.support/fonts/noticia-text-v15-latin-700.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/noticia-text-v15-latin-italic.woff2
Normal file
BIN
doc/odoc.support/fonts/noticia-text-v15-latin-italic.woff2
Normal file
Binary file not shown.
BIN
doc/odoc.support/fonts/noticia-text-v15-latin-regular.woff2
Normal file
BIN
doc/odoc.support/fonts/noticia-text-v15-latin-regular.woff2
Normal file
Binary file not shown.
634
doc/odoc.support/highlight.pack.js
Normal file
634
doc/odoc.support/highlight.pack.js
Normal file
File diff suppressed because one or more lines are too long
1
doc/odoc.support/katex.min.css
vendored
Normal file
1
doc/odoc.support/katex.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
doc/odoc.support/katex.min.js
vendored
Normal file
1
doc/odoc.support/katex.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1393
doc/odoc.support/odoc.css
Normal file
1393
doc/odoc.support/odoc.css
Normal file
File diff suppressed because it is too large
Load diff
66
doc/odoc.support/odoc_search.js
Normal file
66
doc/odoc.support/odoc_search.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* The browsers interpretation of the CORS origin policy prevents to run
|
||||
webworkers from javascript files fetched from the file:// protocol. This hack
|
||||
is to workaround this restriction. */
|
||||
function createWebWorker() {
|
||||
var searchs = search_urls.map((search_url) => {
|
||||
let parts = document.location.href.split("/");
|
||||
parts[parts.length - 1] = search_url;
|
||||
return '"' + parts.join("/") + '"';
|
||||
});
|
||||
blobContents = ["importScripts(" + searchs.join(",") + ");"];
|
||||
var blob = new Blob(blobContents, { type: "application/javascript" });
|
||||
var blobUrl = URL.createObjectURL(blob);
|
||||
|
||||
var worker = new Worker(blobUrl);
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
|
||||
return worker;
|
||||
}
|
||||
|
||||
var worker;
|
||||
var waiting = 0;
|
||||
|
||||
function wait() {
|
||||
waiting = waiting + 1;
|
||||
document.querySelector(".search-snake").classList.add("search-busy");
|
||||
}
|
||||
|
||||
function stop_waiting() {
|
||||
if (waiting > 0) waiting = waiting - 1;
|
||||
else waiting = 0;
|
||||
if (waiting == 0) {
|
||||
document.querySelector(".search-snake").classList.remove("search-busy");
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelector(".search-bar").addEventListener("focus", (ev) => {
|
||||
if (typeof worker == "undefined") {
|
||||
worker = createWebWorker();
|
||||
worker.onmessage = (e) => {
|
||||
stop_waiting();
|
||||
let results = e.data;
|
||||
let search_results = document.querySelector(".search-result");
|
||||
search_results.innerHTML = "";
|
||||
let f = (entry) => {
|
||||
let search_result = document.createElement("a");
|
||||
search_result.classList.add("search-entry");
|
||||
search_result.href = base_url + entry.url;
|
||||
search_result.innerHTML = entry.html;
|
||||
search_results.appendChild(search_result);
|
||||
};
|
||||
results.forEach(f);
|
||||
let search_request = document.querySelector(".search-bar").value;
|
||||
if (results.length == 0 && search_request != "") {
|
||||
let no_result = document.createElement("div");
|
||||
no_result.classList.add("search-no-result");
|
||||
no_result.innerText = "No result...";
|
||||
search_results.appendChild(no_result);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelector(".search-bar").addEventListener("input", (ev) => {
|
||||
wait();
|
||||
worker.postMessage(ev.target.value);
|
||||
});
|
14
doc/ohex/Ohex/index.html
Normal file
14
doc/ohex/Ohex/index.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Ohex (ohex.Ohex)</title><meta charset="utf-8"/><link rel="stylesheet" href="../../odoc.support/odoc.css"/><meta name="generator" content="odoc 2.4.1"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../../odoc.support/highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body class="odoc"><nav class="odoc-nav"><a href="../index.html">Up</a> – <a href="../index.html">ohex</a> » Ohex</nav><header class="odoc-preamble"><h1>Module <code><span>Ohex</span></code></h1><p>Convert from and to hexadecimal representation.</p></header><div class="odoc-content"><div class="odoc-spec"><div class="spec value anchored" id="val-required_length"><a href="#val-required_length" class="anchor"></a><code><span><span class="keyword">val</span> required_length : <span><span class="optlabel">?skip_whitespace</span>:bool <span class="arrow">-></span></span> <span>string <span class="arrow">-></span></span> int</span></code></div><div class="spec-doc"><p><code>required_length ~skip_whitespace s</code> returns the length needed when the hex string <code>s</code> would be decoded into a sequence of octets. The argument <code>skip_whitespace</code> defaults to <code>true</code>, and skips any whitespace characters (' ', '\n', '\r', '\t'). This function is useful for estimating the space required for <code>decode_into</code>.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>if any character in <code>s</code> is not a hex character, or an odd amount of characters are present.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-decode"><a href="#val-decode" class="anchor"></a><code><span><span class="keyword">val</span> decode : <span><span class="optlabel">?skip_whitespace</span>:bool <span class="arrow">-></span></span> <span>string <span class="arrow">-></span></span> string</span></code></div><div class="spec-doc"><p><code>decode ~skip_whitespace s</code> decodes a hex string <code>s</code> into a sequence of octets. The argument <code>skip_whitespace</code> defaults to <code>true</code>, and skips any whitespace characters in <code>s</code> (' ', '\n', '\r', '\t'). An example: <code>decode "4142" = "AB"</code>.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>if any character in <code>s</code> is not a hex character, or an odd amount of characters are present.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-decode_into"><a href="#val-decode_into" class="anchor"></a><code><span><span class="keyword">val</span> decode_into :
|
||||
<span><span class="optlabel">?skip_whitespace</span>:bool <span class="arrow">-></span></span>
|
||||
<span>string <span class="arrow">-></span></span>
|
||||
<span>bytes <span class="arrow">-></span></span>
|
||||
<span><span class="optlabel">?off</span>:int <span class="arrow">-></span></span>
|
||||
<span>unit <span class="arrow">-></span></span>
|
||||
unit</span></code></div><div class="spec-doc"><p><code>decode_into ~skip_whitespace s dst ~off ()</code> decodes <code>s</code> into <code>dst</code> starting at <code>off</code> (defaults to 0). The argument <code>skip_whitespace</code> defaults to <code>true</code> and skips any whitespace characters.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>if any character in <code>s</code> is not a hex character, an odd amount of characters are present, or <code>dst</code> does not contain enough space.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-encode"><a href="#val-encode" class="anchor"></a><code><span><span class="keyword">val</span> encode : <span>string <span class="arrow">-></span></span> string</span></code></div><div class="spec-doc"><p><code>encode s</code> encodes <code>s</code> into a freshly allocated string of double size, where each character in <code>s</code> is encoded as two hex digits in the returned string. An example: <code>encode "AB" = "4142"</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-encode_into"><a href="#val-encode_into" class="anchor"></a><code><span><span class="keyword">val</span> encode_into : <span>string <span class="arrow">-></span></span> <span>bytes <span class="arrow">-></span></span> <span><span class="optlabel">?off</span>:int <span class="arrow">-></span></span> <span>unit <span class="arrow">-></span></span> unit</span></code></div><div class="spec-doc"><p><code>encode_into s dst ~off ()</code> encodes <code>s</code> into <code>dst</code> starting at <code>off</code> (defaults to 0). Each character is encoded as two hex digits in <code>dst</code>.</p><ul class="at-tags"><li class="raises"><span class="at-tag">raises</span> <code>Invalid_argument</code> <p>if <code>dst</code> does not contain enough space.</p></li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-pp"><a href="#val-pp" class="anchor"></a><code><span><span class="keyword">val</span> pp : <span><span class="xref-unresolved">Stdlib</span>.Format.formatter <span class="arrow">-></span></span> <span>string <span class="arrow">-></span></span> unit</span></code></div><div class="spec-doc"><p><code>pp ppf s</code> pretty-prints the string <code>s</code> in hexadecimal. Some spaces are emitted for easier readability. No newline is emitted.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-pp_hexdump"><a href="#val-pp_hexdump" class="anchor"></a><code><span><span class="keyword">val</span> pp_hexdump :
|
||||
<span><span class="optlabel">?row_numbers</span>:bool <span class="arrow">-></span></span>
|
||||
<span><span class="optlabel">?chars</span>:bool <span class="arrow">-></span></span>
|
||||
<span>unit <span class="arrow">-></span></span>
|
||||
<span><span class="xref-unresolved">Stdlib</span>.Format.formatter <span class="arrow">-></span></span>
|
||||
<span>string <span class="arrow">-></span></span>
|
||||
unit</span></code></div><div class="spec-doc"><p><code>pp_hexdump ~row_numbers ~chars () ppf s</code> pretty-prints the string <code>s</code> in hexadecimal (similar to <code>hexdump -C</code>). If <code>row_numbers</code> is provided (defaults to <code>true</code>), each output line is prefixed with the row number. If <code>chars</code> is provided (defaults to <code>true</code>), in the last column the ASCII string is printed (non-printable characters are printed as '.').</p></div></div></div></body></html>
|
2
doc/ohex/index.html
Normal file
2
doc/ohex/index.html
Normal file
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>index (ohex.index)</title><meta charset="utf-8"/><link rel="stylesheet" href="../odoc.support/odoc.css"/><meta name="generator" content="odoc 2.4.1"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../odoc.support/highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body class="odoc"><nav class="odoc-nav"><a href="../index.html">Up</a> – ohex</nav><header class="odoc-preamble"><h1 id="ohex-index"><a href="#ohex-index" class="anchor"></a>ohex index</h1></header><nav class="odoc-toc"><ul><li><a href="#library-ohex">Library ohex</a></li></ul></nav><div class="odoc-content"><h2 id="library-ohex"><a href="#library-ohex" class="anchor"></a>Library ohex</h2><p>The entry point of this library is the module: <a href="Ohex/index.html"><code>Ohex</code></a>.</p></div></body></html>
|
9
dune
9
dune
|
@ -1,9 +0,0 @@
|
|||
(library
|
||||
(name ohex)
|
||||
(public_name ohex)
|
||||
(modules ohex))
|
||||
|
||||
(test
|
||||
(name tests)
|
||||
(modules tests)
|
||||
(libraries alcotest ohex))
|
|
@ -1,3 +0,0 @@
|
|||
(lang dune 2.7)
|
||||
(name ohex)
|
||||
(formatting disabled)
|
121
ohex.ml
121
ohex.ml
|
@ -1,121 +0,0 @@
|
|||
|
||||
let string_fold f acc str =
|
||||
let st = ref acc in
|
||||
String.iter (fun c -> st := f !st c) str;
|
||||
!st
|
||||
|
||||
let is_space = function
|
||||
| ' ' | '\n' | '\r' | '\t' -> true
|
||||
| _ -> false
|
||||
|
||||
let digit = function
|
||||
| '0'..'9' as c -> int_of_char c - 0x30
|
||||
| 'A'..'F' as c -> int_of_char c - 0x41 + 10
|
||||
| 'a'..'f' as c -> int_of_char c - 0x61 + 10
|
||||
| _ -> invalid_arg "bad character"
|
||||
|
||||
let required_length ?(skip_whitespace = true) src =
|
||||
let req =
|
||||
string_fold (fun r c ->
|
||||
if skip_whitespace && is_space c then
|
||||
r
|
||||
else (
|
||||
ignore (digit c);
|
||||
succ r))
|
||||
0 src
|
||||
in
|
||||
if req mod 2 = 0 then
|
||||
req / 2
|
||||
else
|
||||
invalid_arg "leftover byte in hex string"
|
||||
|
||||
let decode_into ?(skip_whitespace = true) src tgt ?(off = 0) () =
|
||||
let fold f acc str =
|
||||
let st = ref acc in
|
||||
String.iter (fun c -> st := f !st c) str;
|
||||
!st
|
||||
in
|
||||
let chars, leftover =
|
||||
fold (fun (chars, leftover) c ->
|
||||
if skip_whitespace && is_space c then
|
||||
chars, leftover
|
||||
else
|
||||
let c = digit c in
|
||||
match leftover with
|
||||
| None -> chars, Some (c lsl 4)
|
||||
| Some c' -> (c' lor c) :: chars, None)
|
||||
([], None) src
|
||||
in
|
||||
let chars = List.rev chars in
|
||||
if leftover <> None then
|
||||
invalid_arg "leftover byte in hex string";
|
||||
List.iteri (fun idx c -> Bytes.set_uint8 tgt (off + idx) c) chars
|
||||
|
||||
let decode ?(skip_whitespace = true) src =
|
||||
let len = required_length ~skip_whitespace src in
|
||||
let buf = Bytes.create len in
|
||||
decode_into ~skip_whitespace src buf ();
|
||||
Bytes.unsafe_to_string buf
|
||||
|
||||
let hex_map = "0123456789abcdef"
|
||||
|
||||
let encode_into src tgt ?(off = 0) () =
|
||||
String.iteri (fun idx c ->
|
||||
let hi, lo =
|
||||
let i = int_of_char c in
|
||||
hex_map.[i lsr 4], hex_map.[i land 0x0F]
|
||||
in
|
||||
Bytes.set tgt (idx * 2 + off) hi;
|
||||
Bytes.set tgt (idx * 2 + off + 1) lo)
|
||||
src
|
||||
|
||||
let encode src =
|
||||
let buf = Bytes.create (String.length src * 2) in
|
||||
encode_into src buf ();
|
||||
Bytes.unsafe_to_string buf
|
||||
|
||||
let printable_ascii c =
|
||||
let i = int_of_char c in
|
||||
not (i < 0x20 || i >= 0x7f)
|
||||
|
||||
let pp ppf s =
|
||||
String.iteri (fun idx c ->
|
||||
Format.fprintf ppf "%02x" (int_of_char c);
|
||||
if idx mod 2 = 1 then
|
||||
Format.pp_print_string ppf " ";
|
||||
if idx mod 8 = 7 then
|
||||
Format.pp_print_string ppf " ")
|
||||
s
|
||||
|
||||
let pp_hexdump ?(row_numbers = true) ?(chars = true) () ppf s =
|
||||
String.iteri (fun idx c ->
|
||||
if idx mod 16 = 0 && row_numbers then
|
||||
Format.fprintf ppf "%06x " idx;
|
||||
Format.fprintf ppf "%02x" (int_of_char c);
|
||||
if idx mod 2 = 1 then
|
||||
Format.pp_print_string ppf " ";
|
||||
if idx mod 8 = 7 then
|
||||
Format.pp_print_string ppf " ";
|
||||
if idx mod 16 = 15 && chars then
|
||||
String.iter (fun c ->
|
||||
Format.pp_print_char ppf (if printable_ascii c then c else '.'))
|
||||
(String.sub s (idx - 15) 16);
|
||||
if idx mod 16 = 15 then
|
||||
Format.pp_print_string ppf "\n")
|
||||
s;
|
||||
(if chars then
|
||||
let last_n, pad =
|
||||
let l = String.length s in
|
||||
let pad = 16 - (l mod 16) in
|
||||
let pad = if pad = 16 then 0 else pad in
|
||||
String.sub s (l - (l mod 16)) (l mod 16),
|
||||
pad
|
||||
in
|
||||
if pad > 0 then
|
||||
let pad_chars = pad * 2 + (pad + 1) / 2 + (if pad > 8 then 1 else 0) + 1 in
|
||||
Format.pp_print_string ppf (String.make pad_chars ' ');
|
||||
String.iter (fun c ->
|
||||
Format.pp_print_char ppf (if printable_ascii c then c else '.'))
|
||||
last_n);
|
||||
if String.length s mod 16 <> 0 then
|
||||
Format.pp_print_string ppf "\n"
|
54
ohex.mli
54
ohex.mli
|
@ -1,54 +0,0 @@
|
|||
(** Convert from and to hexadecimal representation. *)
|
||||
|
||||
val required_length : ?skip_whitespace:bool -> string -> int
|
||||
(** [required_length ~skip_whitespace s] returns the length needed when the
|
||||
hex string [s] would be decoded into a sequence of octets. The argument
|
||||
[skip_whitespace] defaults to [true], and skips any whitespace characters
|
||||
(' ', '\n', '\r', '\t'). This function is useful for estimating the space
|
||||
required for [decode_into].
|
||||
|
||||
@raise Invalid_argument if any character in [s] is not a hex character, or
|
||||
an odd amount of characters are present. *)
|
||||
|
||||
val decode : ?skip_whitespace:bool -> string -> string
|
||||
(** [decode ~skip_whitespace s] decodes a hex string [s] into a sequence of
|
||||
octets. The argument [skip_whitespace] defaults to [true], and skips any
|
||||
whitespace characters in [s] (' ', '\n', '\r', '\t'). An example:
|
||||
[decode "4142" = "AB"].
|
||||
|
||||
@raise Invalid_argument if any character in [s] is not a hex character, or
|
||||
an odd amount of characters are present. *)
|
||||
|
||||
val decode_into : ?skip_whitespace:bool -> string -> bytes -> ?off:int -> unit
|
||||
-> unit
|
||||
(** [decode_into ~skip_whitespace s dst ~off ()] decodes [s] into [dst]
|
||||
starting at [off] (defaults to 0). The argument [skip_whitespace] defaults
|
||||
to [true] and skips any whitespace characters.
|
||||
|
||||
@raise Invalid_argument if any character in [s] is not a hex character, an
|
||||
odd amount of characters are present, or [dst] does not contain enough
|
||||
space. *)
|
||||
|
||||
val encode : string -> string
|
||||
(** [encode s] encodes [s] into a freshly allocated string of double size, where
|
||||
each character in [s] is encoded as two hex digits in the returned string.
|
||||
An example: [encode "AB" = "4142"].
|
||||
*)
|
||||
|
||||
val encode_into : string -> bytes -> ?off:int -> unit -> unit
|
||||
(** [encode_into s dst ~off ()] encodes [s] into [dst] starting at [off]
|
||||
(defaults to 0). Each character is encoded as two hex digits in [dst].
|
||||
|
||||
@raise Invalid_argument if [dst] does not contain enough space. *)
|
||||
|
||||
val pp : Format.formatter -> string -> unit
|
||||
(** [pp ppf s] pretty-prints the string [s] in hexadecimal. Some spaces are
|
||||
emitted for easier readability. No newline is emitted. *)
|
||||
|
||||
val pp_hexdump : ?row_numbers:bool -> ?chars:bool -> unit ->
|
||||
Format.formatter -> string -> unit
|
||||
(** [pp_hexdump ~row_numbers ~chars () ppf s] pretty-prints the string [s] in
|
||||
hexadecimal (similar to [hexdump -C]). If [row_numbers] is provided
|
||||
(defaults to [true]), each output line is prefixed with the row number.
|
||||
If [chars] is provided (defaults to [true]), in the last column the ASCII
|
||||
string is printed (non-printable characters are printed as '.'). *)
|
22
ohex.opam
22
ohex.opam
|
@ -1,22 +0,0 @@
|
|||
opam-version: "2.0"
|
||||
maintainer: "Hannes Mehnert <hannes@mehnert.org>"
|
||||
authors: "Hannes Mehnert <hannes@mehnert.org>"
|
||||
license: "BSD-2-Clause"
|
||||
homepage: "https://git.robur.coop/robur/ohex"
|
||||
doc: "https://robur-coop.github.io/ohex/doc"
|
||||
bug-reports: "https://git.robur.coop/robur/ohex/issues"
|
||||
depends: [
|
||||
"ocaml" {>= "4.08.0"}
|
||||
"dune" {>= "2.7"}
|
||||
"alcotest" {with-test}
|
||||
]
|
||||
build: [
|
||||
["dune" "subst"] {dev}
|
||||
["dune" "build" "-p" name "-j" jobs]
|
||||
["dune" "runtest" "-p" name "-j" jobs] {with-test}
|
||||
]
|
||||
dev-repo: "git+https://git.robur.coop/robur/ohex.git"
|
||||
synopsis: "Hexadecimal encoding and decoding"
|
||||
description: """
|
||||
A library to encode and decode hexadecimal byte sequences.
|
||||
"""
|
102
tests.ml
102
tests.ml
|
@ -1,102 +0,0 @@
|
|||
|
||||
let tests = [
|
||||
"", 0, "";
|
||||
"41", 1, "A";
|
||||
"41 41", 2, "AA";
|
||||
" 41 41 ", 2, "AA";
|
||||
" 414 1", 2, "AA";
|
||||
]
|
||||
|
||||
let len_dec_tests =
|
||||
List.mapi (fun i (s, len, v) ->
|
||||
string_of_int i ^ " is correct", `Quick,
|
||||
(fun () ->
|
||||
Alcotest.(check int "required length" len (Ohex.required_length s));
|
||||
Alcotest.(check string "decode works fine" v (Ohex.decode s))))
|
||||
tests
|
||||
|
||||
let bad_char_input = [ "W" ; "AAWW" ; "WWAA" ]
|
||||
|
||||
let leftover_input = [ "AAA" ; "A" ]
|
||||
|
||||
let bad_input_ws = [ " "; " AA" ; "AA " ; "A A" ]
|
||||
|
||||
let bad_len_dec_tests =
|
||||
(List.mapi (fun i s ->
|
||||
string_of_int i ^ " fails (bad character)", `Quick,
|
||||
(fun () ->
|
||||
Alcotest.(check_raises "required length raises"
|
||||
(Invalid_argument "bad character")
|
||||
(fun () -> ignore (Ohex.required_length s)));
|
||||
Alcotest.(check_raises "decode raises"
|
||||
(Invalid_argument "bad character")
|
||||
(fun () -> ignore (Ohex.decode s)))))
|
||||
bad_char_input) @
|
||||
(List.mapi (fun i s ->
|
||||
string_of_int i ^ " fails (leftover)", `Quick,
|
||||
(fun () ->
|
||||
Alcotest.(check_raises "required length raises"
|
||||
(Invalid_argument "leftover byte in hex string")
|
||||
(fun () -> ignore (Ohex.required_length ~skip_whitespace:false s)));
|
||||
Alcotest.(check_raises "decode raises"
|
||||
(Invalid_argument "leftover byte in hex string")
|
||||
(fun () -> ignore (Ohex.decode ~skip_whitespace:false s)))))
|
||||
leftover_input) @
|
||||
(List.mapi (fun i s ->
|
||||
string_of_int i ^ " fails (skip_whitespace = false)", `Quick,
|
||||
(fun () ->
|
||||
Alcotest.(check_raises "required length raises"
|
||||
(Invalid_argument "bad character")
|
||||
(fun () -> ignore (Ohex.required_length ~skip_whitespace:false s)));
|
||||
Alcotest.(check_raises "decode raises"
|
||||
(Invalid_argument "bad character")
|
||||
(fun () -> ignore (Ohex.decode ~skip_whitespace:false s)))))
|
||||
bad_input_ws)
|
||||
|
||||
let enc_tests = [
|
||||
"A", "41", 2;
|
||||
"AA", "4141", 4;
|
||||
"AAA", "414141", 6;
|
||||
]
|
||||
|
||||
let enc_tests =
|
||||
List.mapi (fun i (v, hex, l) ->
|
||||
string_of_int i ^ " is correct", `Quick,
|
||||
(fun () ->
|
||||
Alcotest.(check string "encode works" hex (Ohex.encode v));
|
||||
let buf = Bytes.create l in
|
||||
Ohex.encode_into v buf ~off:0 ();
|
||||
Alcotest.(check string "encode_into works" hex (Bytes.unsafe_to_string buf))))
|
||||
enc_tests
|
||||
|
||||
let dec_enc () =
|
||||
let random_string () =
|
||||
let size = Random.int 128 in
|
||||
let buf = Bytes.create size in
|
||||
for i = 0 to size - 1 do
|
||||
Bytes.set_uint8 buf i (Random.int 256)
|
||||
done;
|
||||
Bytes.unsafe_to_string buf
|
||||
in
|
||||
for i = 0 to 10_000 do
|
||||
let input = random_string () in
|
||||
Alcotest.(check string ("dec (enc s) = s " ^ string_of_int i)
|
||||
input Ohex.(decode (encode input)));
|
||||
Alcotest.(check string ("dec ~skip_ws:false (enc s) = s " ^ string_of_int i)
|
||||
input Ohex.(decode ~skip_whitespace:false (encode input)));
|
||||
let buf = Bytes.create (String.length input * 2) in
|
||||
Ohex.encode_into input buf ~off:0 ();
|
||||
let out = Bytes.create (String.length input) in
|
||||
Ohex.decode_into (Bytes.unsafe_to_string buf) out ~off:0 ();
|
||||
Alcotest.(check string ("dec_into (enc_into s) = s " ^ string_of_int i)
|
||||
input (Bytes.unsafe_to_string out))
|
||||
done
|
||||
|
||||
let suites = [
|
||||
"length and decode pass", len_dec_tests ;
|
||||
"bad input", bad_len_dec_tests ;
|
||||
"encode tests", enc_tests ;
|
||||
"decode encode", [ "decode (encode s) = s", `Quick, dec_enc ];
|
||||
]
|
||||
|
||||
let () = Alcotest.run "hex tests" suites
|
Loading…
Reference in a new issue