0 | module Data.Hex
 1 |
 2 | import Data.Bits
 3 | import Data.List
 4 |
 5 | %default total
 6 |
 7 | export
 8 | parseHex : Char -> Maybe (Fin 16)
 9 | parseHex '0' = Just 0
10 | parseHex '1' = Just 1
11 | parseHex '2' = Just 2
12 | parseHex '3' = Just 3
13 | parseHex '4' = Just 4
14 | parseHex '5' = Just 5
15 | parseHex '6' = Just 6
16 | parseHex '7' = Just 7
17 | parseHex '8' = Just 8
18 | parseHex '9' = Just 9
19 | parseHex 'a' = Just 10
20 | parseHex 'A' = Just 10
21 | parseHex 'b' = Just 11
22 | parseHex 'B' = Just 11
23 | parseHex 'c' = Just 12
24 | parseHex 'C' = Just 12
25 | parseHex 'd' = Just 13
26 | parseHex 'D' = Just 13
27 | parseHex 'e' = Just 14
28 | parseHex 'E' = Just 14
29 | parseHex 'f' = Just 15
30 | parseHex 'F' = Just 15
31 | parseHex _ = Nothing
32 |
33 | export
34 | hexDigit : Fin 16 -> Char
35 | hexDigit 0 = '0'
36 | hexDigit 1 = '1'
37 | hexDigit 2 = '2'
38 | hexDigit 3 = '3'
39 | hexDigit 4 = '4'
40 | hexDigit 5 = '5'
41 | hexDigit 6 = '6'
42 | hexDigit 7 = '7'
43 | hexDigit 8 = '8'
44 | hexDigit 9 = '9'
45 | hexDigit 10 = 'a'
46 | hexDigit 11 = 'b'
47 | hexDigit 12 = 'c'
48 | hexDigit 13 = 'd'
49 | hexDigit 14 = 'e'
50 | hexDigit 15 = 'f'
51 |
52 | export
53 | leftPad : Char -> Nat -> String -> String
54 | leftPad paddingChar padToLength str =
55 |   if length str < padToLength
56 |     then pack (List.replicate (minus padToLength (length str)) paddingChar) ++ str
57 |     else str
58 |
59 | hexListLittleEndianToInteger : List (Fin 16) -> Integer
60 | hexListLittleEndianToInteger = go 1
61 |   where
62 |     go : Integer -> List (Fin 16) -> Integer
63 |     go multiplier [] = 0
64 |     go multiplier (d :: ds) = cast d * multiplier + go (16 * multiplier) ds
65 |
66 | ||| Convert little-endian hex-string to Integer.
67 | ||| Fails if the string doesn't represent a hexadecimal number.
68 | ||| As for the latin letters in the hex-string, both lower- and upper- case letters represent valid hex characters.
69 | ||| Examples of valid hex-strings:
70 | ||| FFF ✔
71 | ||| fEA ✔
72 | ||| hello ✗
73 | ||| 1F62aA7 ✔
74 | export
75 | fromHexLittleEndian : String -> Maybe Integer
76 | fromHexLittleEndian str = do
77 |   hexList <- traverse parseHex (unpack str)
78 |   Just (hexListLittleEndianToInteger hexList)
79 |
80 | ||| Just like `fromHexLittleEndian` but for big-endian hex-strings.
81 | export
82 | fromHexBigEndian : String -> Maybe Integer
83 | fromHexBigEndian str = do
84 |   hexList <- traverse parseHex (reverse (unpack str))
85 |   Just (hexListLittleEndianToInteger hexList)
86 |