module EVM.Hexdump (prettyHex, simpleHex) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as B (length, unpack)
import qualified Data.ByteString.Char8 as B8 (unpack)
import Data.Char (isAscii, isControl)
import Data.List (intercalate, transpose, unfoldr)
import Numeric (showHex)
byteWidth :: Num a => a
byteWidth :: forall a. Num a => a
byteWidth = a
2
numWordBytes :: Num a => a
numWordBytes :: forall a. Num a => a
numWordBytes = a
4
prettyHex :: Int -> ByteString -> String
prettyHex :: Int -> ByteString -> [Char]
prettyHex Int
hexDisplayWidth ByteString
bs = [[Char]] -> [Char]
unlines ([Char]
header forall a. a -> [a] -> [a]
: [[Char]]
body)
where
numLineWords :: Int
numLineWords = Int
4
addressWidth :: Int
addressWidth = Int
4
numLineBytes :: Int
numLineBytes = Int
numLineWords forall a. Num a => a -> a -> a
* forall a. Num a => a
numWordBytes
replacementChar :: Char
replacementChar = Char
'.'
header :: [Char]
header = [Char]
"Length: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show (ByteString -> Int
B.length ByteString
bs)
forall a. [a] -> [a] -> [a]
++ [Char]
" (0x" forall a. [a] -> [a] -> [a]
++ forall a. (Integral a, Show a) => a -> ShowS
showHex (ByteString -> Int
B.length ByteString
bs) [Char]
") bytes"
body :: [[Char]]
body = forall a b. (a -> b) -> [a] -> [b]
map (forall a. [a] -> [[a]] -> [a]
intercalate [Char]
" ")
forall a b. (a -> b) -> a -> b
$ forall a. [[a]] -> [[a]]
transpose [[[Char]]
mkLineNumbers, ByteString -> [[Char]]
mkHexDisplay ByteString
bs, ByteString -> [[Char]]
mkAsciiDump ByteString
bs]
mkHexDisplay :: ByteString -> [[Char]]
mkHexDisplay
= Int -> [[Char]] -> [[Char]]
padLast Int
hexDisplayWidth
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall a. [a] -> [[a]] -> [a]
intercalate [Char]
" ") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> [a] -> [[a]]
group Int
numLineWords
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall a. [a] -> [[a]] -> [a]
intercalate [Char]
" ") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> [a] -> [[a]]
group forall a. Num a => a
numWordBytes
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall a. (Show a, Integral a) => Int -> a -> [Char]
paddedShowHex forall a. Num a => a
byteWidth)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
B.unpack
mkAsciiDump :: ByteString -> [[Char]]
mkAsciiDump = forall a. Int -> [a] -> [[a]]
group Int
numLineBytes forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
cleanString forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Char]
B8.unpack
cleanString :: ShowS
cleanString = forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
go
where
go :: Char -> Char
go Char
x | Char -> Bool
isWorthPrinting Char
x = Char
x
| Bool
otherwise = Char
replacementChar
mkLineNumbers :: [[Char]]
mkLineNumbers = [forall a. (Show a, Integral a) => Int -> a -> [Char]
paddedShowHex Int
addressWidth (Int
x forall a. Num a => a -> a -> a
* Int
numLineBytes) forall a. [a] -> [a] -> [a]
++ [Char]
":"
| Int
x <- [Int
0 .. (ByteString -> Int
B.length ByteString
bs forall a. Num a => a -> a -> a
- Int
1) forall a. Integral a => a -> a -> a
`div` Int
numLineBytes] ]
padLast :: Int -> [[Char]] -> [[Char]]
padLast Int
w [[Char]
x] = [[Char]
x forall a. [a] -> [a] -> [a]
++ forall a. Int -> a -> [a]
replicate (Int
w forall a. Num a => a -> a -> a
- forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
x) Char
' ']
padLast Int
w ([Char]
x:[[Char]]
xs) = [Char]
x forall a. a -> [a] -> [a]
: Int -> [[Char]] -> [[Char]]
padLast Int
w [[Char]]
xs
padLast Int
_ [] = []
paddedShowHex :: (Show a, Integral a) => Int -> a -> String
paddedShowHex :: forall a. (Show a, Integral a) => Int -> a -> [Char]
paddedShowHex Int
w a
n = [Char]
pad forall a. [a] -> [a] -> [a]
++ [Char]
str
where
str :: [Char]
str = forall a. (Integral a, Show a) => a -> ShowS
showHex a
n [Char]
""
pad :: [Char]
pad = forall a. Int -> a -> [a]
replicate (Int
w forall a. Num a => a -> a -> a
- forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
str) Char
'0'
simpleHex :: ByteString -> String
simpleHex :: ByteString -> [Char]
simpleHex = forall a. [a] -> [[a]] -> [a]
intercalate [Char]
" "
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall a. [a] -> [[a]] -> [a]
intercalate [Char]
" ") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> [a] -> [[a]]
group forall a. Num a => a
numWordBytes
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall a. (Show a, Integral a) => Int -> a -> [Char]
paddedShowHex forall a. Num a => a
byteWidth)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
B.unpack
isWorthPrinting :: Char -> Bool
isWorthPrinting :: Char -> Bool
isWorthPrinting Char
x = Char -> Bool
isAscii Char
x Bool -> Bool -> Bool
&& Bool -> Bool
not (Char -> Bool
isControl Char
x)
group :: Int -> [a] -> [[a]]
group :: forall a. Int -> [a] -> [[a]]
group Int
n
| Int
n forall a. Ord a => a -> a -> Bool
<= Int
0 = (forall a. a -> [a] -> [a]
:[])
| Bool
otherwise = forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr [a] -> Maybe ([a], [a])
go
where
go :: [a] -> Maybe ([a], [a])
go [] = forall a. Maybe a
Nothing
go [a]
xs = forall a. a -> Maybe a
Just (forall a. Int -> [a] -> ([a], [a])
splitAt Int
n [a]
xs)