summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Crayne <jim.crayne@gmail.com>2017-11-14 06:49:03 +0000
committerJames Crayne <jim.crayne@gmail.com>2017-11-15 23:36:57 +0000
commit3ce72e7bc8ae7cdb7b69f42b1dfcbe4cb05f12ce (patch)
treeaa69c67ce6ac2bad8c668d7e1c5f40f19c5b6822
parent320de9e7fda65182a7c75b7e68046aa327503cd9 (diff)
xxd on ByteArrayAccess, and xxd2 for ascii dump
-rw-r--r--src/Text/XXD.hs43
1 files changed, 38 insertions, 5 deletions
diff --git a/src/Text/XXD.hs b/src/Text/XXD.hs
index d835b238..04c458a7 100644
--- a/src/Text/XXD.hs
+++ b/src/Text/XXD.hs
@@ -1,23 +1,56 @@
1{-# LANGUAGE ScopedTypeVariables #-}
1module Text.XXD where 2module Text.XXD where
2 3
3import qualified Data.ByteString.Base16 as Base16 4import qualified Data.ByteString.Base16 as Base16
4import Data.ByteString (ByteString) 5import Data.ByteString (ByteString)
5import qualified Data.ByteString as B 6import qualified Data.ByteString as B
7import Data.ByteArray (ByteArrayAccess,ByteArray)
8import qualified Data.ByteArray as BA
6import Data.Word 9import Data.Word
7import Data.Bits 10import Data.Bits
8import Data.Char 11import Data.Char
12import Data.List
9import Text.Printf 13import Text.Printf
10 14
11nibble :: Word8 -> Char 15nibble :: Word8 -> Char
12nibble b = intToDigit (fromIntegral (b .&. 0x0F)) 16nibble b = intToDigit (fromIntegral (b .&. 0x0F))
13 17
14xxd :: Int -> ByteString -> [String] 18xxd :: (ByteArrayAccess ba) => Int -> ba -> [String]
15xxd offset bs | B.null bs = [] 19xxd offset bs | BA.null bs = []
16xxd offset bs = printf "%03x: %s" offset ds : xxd (offset + B.length xs) bs' 20xxd offset bs = printf "%03x: %s" offset ds : xxd (offset + BA.length xs) bs'
17 where 21 where
18 ds = unwords $ map (\byte -> [nibble (byte `shiftR` 4), nibble byte]) 22 ds = unwords $ map (\byte -> [nibble (byte `shiftR` 4), nibble byte])
19 $ B.unpack xs 23 $ BA.unpack xs
20 (xs,bs') = B.splitAt 16 bs 24 (xs,bs') = splitAtView 16 bs
25
26splitAtView :: (ByteArrayAccess ba) => Int -> ba -> (BA.View ba, BA.View ba)
27splitAtView n bs = (BA.takeView bs n, BA.dropView bs n)
28
29-- | like xxd, but also shows ascii
30xxd2 :: forall a. ByteArrayAccess a => Int -> a -> String
31xxd2 offset bs | BA.null bs = []
32xxd2 offset bs
33 = let xs = xxd offset bs
34 as = map myunpack $ every16Bytes bs -- (BA.view bs 0 (BA.length bs))
35 cs = zipWith (\x y -> [x,y]) xs as
36 in showColumns cs
37 where
38 myunpack s = map word8tochar (BA.unpack s)
39 where word8tochar w = let c = chr (fromIntegral w)
40 in if isPrint c then c else '.'
41 every16Bytes :: a -> [BA.View a]
42 every16Bytes bs = let l = BA.length bs
43 (ld,lm) = l `divMod` 16
44 offsets = [0 .. ld ]
45 lens = replicate (ld ) 16 ++ [lm]
46 in zipWith (\o l -> BA.view bs (o*16) l) offsets lens
47 showColumns :: [[String]] -> String
48 showColumns rows = do
49 let cols = transpose rows
50 ws = map (maximum . map (succ . length)) cols
51 fs <- rows
52 _ <- take 1 fs -- Guard against empty rows so that 'last' is safe.
53 " " ++ concat (zipWith (printf "%-*s") (init ws) (init fs)) ++ last fs ++ "\n"
21 54
22{- 55{-
23main = do 56main = do