Add string-to-hex and back conversions

Add parseHexStr and toHex and tests.
This commit is contained in:
Federico Ceratto
2017-10-15 22:02:52 +01:00
parent 5e93eb9d7a
commit 4100932a4b
2 changed files with 68 additions and 0 deletions

View File

@@ -930,6 +930,19 @@ proc toHex*[T](x: T): string =
## Shortcut for ``toHex(x, T.sizeOf * 2)``
toHex(BiggestInt(x), T.sizeOf * 2)
proc toHex*(s: string): string {.noSideEffect, rtl.} =
## Converts a bytes string to its hexadecimal representation.
##
## The output is twice the input long. No prefix like
## ``0x`` is generated.
const HexChars = "0123456789ABCDEF"
result = newString(s.len * 2)
for pos, c in s:
var n = ord(c)
result[pos * 2 + 1] = HexChars[n and 0xF]
n = n shr 4
result[pos * 2] = HexChars[n]
proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect,
rtl, extern: "nsuIntToStr".} =
## Converts `x` to its decimal representation.
@@ -1012,6 +1025,43 @@ proc parseHexInt*(s: string): int {.noSideEffect, procvar,
of '\0': break
else: raise newException(ValueError, "invalid integer: " & s)
proc generateHexCharToValueMap(): string =
## Generate a string to map a hex digit to uint value
result = ""
for inp in 0..255:
let ch = chr(inp)
let o =
case ch:
of '0'..'9': inp - ord('0')
of 'a'..'f': inp - ord('a') + 10
of 'A'..'F': inp - ord('A') + 10
else: 17 # indicates an invalid hex char
result.add chr(o)
const hexCharToValueMap = generateHexCharToValueMap()
proc parseHexStr*(s: string): string {.noSideEffect, procvar,
rtl, extern: "nsuParseHexStr".} =
## Convert hex-encoded string to byte string, e.g.:
##
## .. code-block:: nim
## hexToStr("00ff") == "\0\255"
##
## Raises ``ValueError`` for an invalid hex values. The comparison is
## case-insensitive.
if s.len mod 2 != 0:
raise newException(ValueError, "Incorrect hex string len")
result = newString(s.len div 2)
var buf = 0
for pos, c in s:
let val = hexCharToValueMap[ord(c)].ord
if val == 17:
raise newException(ValueError, "Invalid hex char " & repr(c))
if pos mod 2 == 0:
buf = val
else:
result[pos div 2] = chr(val + buf shl 4)
proc parseBool*(s: string): bool =
## Parses a value into a `bool`.
##

View File

@@ -229,6 +229,24 @@ assert "/1/2/3".rfind('0') == -1
assert(toHex(100i16, 32) == "00000000000000000000000000000064")
assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C")
assert "".parseHexStr == ""
assert "00Ff80".parseHexStr == "\0\xFF\x80"
try:
discard "00Ff8".parseHexStr
assert false, "Should raise ValueError"
except ValueError:
discard
try:
discard "0k".parseHexStr
assert false, "Should raise ValueError"
except ValueError:
discard
assert "".toHex == ""
assert "\x00\xFF\x80".toHex == "00FF80"
assert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF"
assert(' '.repeat(8)== " ")
assert(" ".repeat(8) == " ")
assert(spaces(8) == " ")