Skip to content

Instantly share code, notes, and snippets.

@line-o
Last active August 8, 2021 20:16
Show Gist options
  • Save line-o/0d3003a136e0c10dc97e3a9836713a9e to your computer and use it in GitHub Desktop.
Save line-o/0d3003a136e0c10dc97e3a9836713a9e to your computer and use it in GitHub Desktop.
Convert hex string to xs:integer
xquery version "3.1";
(:
: Parts of gist were taken from by https://mathling.com/code/art/core/utilities.xqy
: Copyright Mary Holstege 2020-2021
: Licensed under CC-BY (https://creativecommons.org/licenses/by/4.0/)
:
: Parts are from the xbow library https://github.com/line-o/xbow
: by Juri Leino
: Licensed under MIT
:)
(: This is a copy of xbow:sequence-for-each-index :)
declare
function local:for-each-index ($seq as item()*, $func as function(*)) as item()* {
fold-left($seq, [0, ()], function ($result as array(*), $next as item()) {
let $pos := $result?1 + 1
return [$pos, ($result?2, $func($next, $pos))]
})?2
};
(:
: This is a pre-release of xbow:test
: If $test($item) evaluates to true then then $then($item) will be returned otherwise $item
: will be returned unchanged.
:
: xbow:test will be part of an upcoming release of xbow with several control flow helpers
:)
declare
function local:test ($item as item()*, $test as function(item()*) as item()*, $then as function(*)) as item()* {
if ($test($item))
then ($then($item))
else ($item)
};
(:
: storing all valid hexdigit characters in a sequence allows to get the value
: from its position
:)
declare
variable $local:hexdigits := (
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, (: 0 to 9 :)
97, 98, 99, 100, 101, 102 (: a to f :)
);
(:
: This is extracted and modified
: from https://mathling.com/code/art/core/utilities.xqy this:hex-to-integer
: since hex2int executes lower-case() we do not have to deal with uppercase
: characters here anymore, also rewritten to get hexdigit value from position
:)
declare
function local:hexdigit2int ($cp as xs:integer, $pos as xs:integer) as xs:integer {
if ($cp = $local:hexdigits)
then (index-of($local:hexdigits, $cp) - 1) * math:pow(16, $pos - 1)
else error(
xs:QName("invalid-hexdigit"),
"'" || codepoints-to-string($cp) || "' at position " || $pos)
};
(:
: This was extracted from https://mathling.com/code/art/core/utilities.xqy this:hex-to-integer
: hexstrings more than 16 characters long would exceed MAX_INT: 9223372036854775807
:)
declare
function local:exceeds-max-int ($hexstring as xs:string) as xs:boolean {
string-length($hexstring) > 16
};
(: return true, if $s has leading zeros :)
declare
function local:check-for-leading-zeros ($s as xs:string) as xs:boolean {
starts-with($s, "0")
};
(: remove leading zeros from $s :)
declare
function local:replace-leading-zeros ($s as xs:string) as xs:string {
replace($s, "^0+", "")
};
(:
: This is an adapted version of this:hex-to-integer
: from https://mathling.com/code/art/core/utilities.xqy
: handles leading zeros,
: converts string to lower case for local:hexdigit2int#2
:)
declare
function local:hex2int ($hex as xs:string) as xs:integer {
$hex
=> local:test(
local:check-for-leading-zeros#1,
local:replace-leading-zeros#1)
=> local:test(
local:exceeds-max-int#1,
error(xs:QName("hexstring-too-long"), ?))
=> lower-case()
=> string-to-codepoints()
=> reverse()
=> local:for-each-index(local:hexdigit2int#2)
=> sum()
};
local:hex2int("00000000000000ffffff")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment