diff options
author | James Crayne <jim.crayne@gmail.com> | 2017-11-14 06:49:03 +0000 |
---|---|---|
committer | James Crayne <jim.crayne@gmail.com> | 2017-11-15 23:36:57 +0000 |
commit | 3ce72e7bc8ae7cdb7b69f42b1dfcbe4cb05f12ce (patch) | |
tree | aa69c67ce6ac2bad8c668d7e1c5f40f19c5b6822 | |
parent | 320de9e7fda65182a7c75b7e68046aa327503cd9 (diff) |
xxd on ByteArrayAccess, and xxd2 for ascii dump
-rw-r--r-- | src/Text/XXD.hs | 43 |
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 #-} | ||
1 | module Text.XXD where | 2 | module Text.XXD where |
2 | 3 | ||
3 | import qualified Data.ByteString.Base16 as Base16 | 4 | import qualified Data.ByteString.Base16 as Base16 |
4 | import Data.ByteString (ByteString) | 5 | import Data.ByteString (ByteString) |
5 | import qualified Data.ByteString as B | 6 | import qualified Data.ByteString as B |
7 | import Data.ByteArray (ByteArrayAccess,ByteArray) | ||
8 | import qualified Data.ByteArray as BA | ||
6 | import Data.Word | 9 | import Data.Word |
7 | import Data.Bits | 10 | import Data.Bits |
8 | import Data.Char | 11 | import Data.Char |
12 | import Data.List | ||
9 | import Text.Printf | 13 | import Text.Printf |
10 | 14 | ||
11 | nibble :: Word8 -> Char | 15 | nibble :: Word8 -> Char |
12 | nibble b = intToDigit (fromIntegral (b .&. 0x0F)) | 16 | nibble b = intToDigit (fromIntegral (b .&. 0x0F)) |
13 | 17 | ||
14 | xxd :: Int -> ByteString -> [String] | 18 | xxd :: (ByteArrayAccess ba) => Int -> ba -> [String] |
15 | xxd offset bs | B.null bs = [] | 19 | xxd offset bs | BA.null bs = [] |
16 | xxd offset bs = printf "%03x: %s" offset ds : xxd (offset + B.length xs) bs' | 20 | xxd 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 | |||
26 | splitAtView :: (ByteArrayAccess ba) => Int -> ba -> (BA.View ba, BA.View ba) | ||
27 | splitAtView n bs = (BA.takeView bs n, BA.dropView bs n) | ||
28 | |||
29 | -- | like xxd, but also shows ascii | ||
30 | xxd2 :: forall a. ByteArrayAccess a => Int -> a -> String | ||
31 | xxd2 offset bs | BA.null bs = [] | ||
32 | xxd2 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 | {- |
23 | main = do | 56 | main = do |