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