asif-6.0.1: app/App/Dump.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module App.Dump
( dumpSegment
) where
import Arbor.File.Format.Asif.Data.Ip
import Arbor.File.Format.Asif.Extract
import Arbor.File.Format.Asif.Segment
import Arbor.File.Format.Asif.Whatever
import Control.Lens
import Control.Monad
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Resource (MonadResource)
import Data.Char (isPrint)
import Data.Generics.Product.Any
import Data.List
import Data.Monoid ((<>))
import Data.Text (Text)
import Data.Thyme.Format (formatTime)
import Data.Thyme.Time.Core
import HaskellWorks.Data.Bits.BitShow
import Numeric (showHex)
import System.IO (Handle)
import System.Locale (defaultTimeLocale, iso8601DateFormat)
import qualified Arbor.File.Format.Asif.ByteString.Lazy as LBS
import qualified Arbor.File.Format.Asif.Format as F
import qualified Arbor.File.Format.Asif.Get as D
import qualified Data.Binary as G
import qualified Data.Binary.Get as G
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Lazy.Char8 as LBSC
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified HaskellWorks.Data.Network.Ip.Ipv4 as IP4
import qualified HaskellWorks.Data.Network.Ip.Ipv6 as IP6
import qualified System.IO as IO
{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
{-# ANN module ("HLint: ignore Redundant do" :: String) #-}
showTime :: FormatTime t => t -> String
showTime = formatTime defaultTimeLocale (iso8601DateFormat (Just "%H:%M:%S %Z"))
dumpSegment :: MonadResource m => Handle -> Int -> Text -> Segment LBS.ByteString -> m ()
dumpSegment hOut i filename segment = do
if T.null filename
then liftIO $ IO.hPutStrLn hOut $ "==== [" <> show i <> "] ===="
else liftIO $ IO.hPutStrLn hOut $ "==== [" <> show i <> "] " <> T.unpack filename <> " ===="
case segment ^. the @"meta" . the @"format" of
Just (Known F.StringZ) -> do
when (LBS.length (segment ^. the @"payload") > 0) $
forM_ (init (LBS.split 0 (segment ^. the @"payload"))) $ \bs ->
liftIO $ IO.hPutStrLn hOut $ T.unpack (T.decodeUtf8 (LBS.toStrict bs))
Just (Known (F.Repeat n F.Char)) ->
forM_ (LBS.chunkBy (fromIntegral n) (segment ^. the @"payload")) $ \bs ->
liftIO $ IO.hPutStrLn hOut $ T.unpack (T.decodeUtf8 (LBS.toStrict bs))
Just (Known F.TimeMillis64LE) ->
forM_ (LBS.chunkBy 8 (segment ^. the @"payload")) $ \bs -> do
let t = G.runGet D.getTimeMillis (LBS.take 8 (bs <> LBS.replicate 8 0))
let ms = t & utcTimeToPOSIXSeconds & toMicroseconds & (`div` 1000)
liftIO $ IO.hPutStrLn hOut $ showTime t <> " (" <> show ms <> " ms)"
Just (Known F.TimeMicros64LE) ->
forM_ (LBS.chunkBy 8 (segment ^. the @"payload")) $ \bs -> do
let t = G.runGet D.getTimeMicros (LBS.take 8 (bs <> LBS.replicate 8 0))
let micros = t & utcTimeToPOSIXSeconds & toMicroseconds
liftIO $ IO.hPutStrLn hOut $ showTime t <> " (" <> show micros <> " µs)"
Just (Known F.Ipv4) ->
forM_ (LBS.chunkBy 4 (segment ^. the @"payload")) $ \bs -> do
let w = G.runGet D.getIpv4 (LBS.take 4 (bs <> LBS.replicate 4 0))
let ipString = w & ipv4ToString
liftIO $ IO.hPutStrLn hOut $ ipString <> replicate (16 - length ipString) ' ' <> "(" <> show w <> ")"
Just (Known F.Ipv6) ->
forM_ (LBS.chunkBy 16 (segment ^. the @"payload")) $ \bs -> do
let ip6@(IP6.IpAddress (a,b,c,d)) = G.runGet D.getIpv6 (LBS.take 16 (bs <> LBS.replicate 16 0))
let ipString = ipv6toStringCollapseV4 ip6
let raw = case isIpv4 ip6 of
Just (IP4.IpAddress w32) -> "(" <> show w32 <> ")"
Nothing -> "(" <> show (a, b, c, d) <> ")"
liftIO $ IO.hPutStrLn hOut $ ipString <> replicate (64 - length ipString) ' ' <> raw
Just (Known F.Ipv4Block) ->
forM_ (LBS.chunkBy 5 (segment ^. the @"payload")) $ \bs -> do
let block@(IP4.IpBlock ip mask) = G.runGet D.getIpv4Block (LBS.take 5 (bs <> LBS.replicate 5 0))
let IP4.IpAddress ipw = ip
let IP4.IpNetMask maskw = mask
let ipString = block & ipv4CidrToString
liftIO $ IO.hPutStrLn hOut $ ipString <> replicate (64 - length ipString) ' ' <> "(" <> show (ipw, maskw) <> ")"
Just (Known F.Ipv6Block) ->
forM_ (LBS.chunkBy 17 (segment ^. the @"payload")) $ \bs -> do
let block@(IP6.IpBlock ip mask) = G.runGet D.getIpv6Block (LBS.take 17 (bs <> LBS.replicate 17 0))
let IP6.IpAddress ipw = ip
let IP6.IpNetMask maskw = mask
let ipString = block & ipv6CidrToStringCollapseV4
liftIO $ IO.hPutStrLn hOut $ ipString <> replicate (64 - length ipString) ' ' <> "(" <> show (ipw, maskw) <> ")"
Just (Known F.Int64LE) ->
forM_ (LBS.chunkBy 8 (segment ^. the @"payload")) $ \bs -> do
let w = G.runGet G.getInt64le (LBS.take 8 (bs <> LBS.replicate 8 0))
liftIO $ IO.hPrint hOut w
Just (Known F.Int32LE) ->
forM_ (LBS.chunkBy 4 (segment ^. the @"payload")) $ \bs -> do
let w = G.runGet G.getInt32le (LBS.take 4 (bs <> LBS.replicate 4 0))
liftIO $ IO.hPrint hOut w
Just (Known F.Int16LE) ->
forM_ (LBS.chunkBy 2 (segment ^. the @"payload")) $ \bs -> do
let w = G.runGet G.getInt16le (LBS.take 2 (bs <> LBS.replicate 2 0))
liftIO $ IO.hPrint hOut w
Just (Known F.Int8) ->
forM_ (LBS.chunkBy 1 (segment ^. the @"payload")) $ \bs -> do
let w = G.runGet G.getInt8 (LBS.take 1 (bs <> LBS.replicate 1 0))
liftIO $ IO.hPrint hOut w
Just (Known F.Word64LE) ->
forM_ (LBS.chunkBy 8 (segment ^. the @"payload")) $ \bs -> do
let w = G.runGet G.getWord64le (LBS.take 8 (bs <> LBS.replicate 8 0))
liftIO $ IO.hPrint hOut w
Just (Known F.Word32LE) ->
forM_ (LBS.chunkBy 4 (segment ^. the @"payload")) $ \bs -> do
let w = G.runGet G.getWord32le (LBS.take 4 (bs <> LBS.replicate 4 0))
liftIO $ IO.hPrint hOut w
Just (Known F.Word16LE) ->
forM_ (LBS.chunkBy 2 (segment ^. the @"payload")) $ \bs -> do
let w = G.runGet G.getWord16le (LBS.take 2 (bs <> LBS.replicate 2 0))
liftIO $ IO.hPrint hOut w
Just (Known F.Word8) ->
forM_ (LBS.chunkBy 1 (segment ^. the @"payload")) $ \bs -> do
let w = G.runGet G.getWord8 (LBS.take 1 (bs <> LBS.replicate 1 0))
liftIO $ IO.hPrint hOut w
Just (Known F.Text) ->
liftIO $ LBSC.hPutStrLn hOut (segment ^. the @"payload")
Just (Known F.BitString) ->
liftIO $ IO.hPutStrLn hOut (bitShow (segment ^. the @"payload"))
Just (Known F.Bitmap) ->
forM_ (bitmap $ segment ^. the @"payload") $ \ip ->
let ipString = ipv4ToString ip
w32 = ipv4ToWord32 ip
in liftIO $ IO.hPutStrLn hOut $ ipString <> replicate (16 - length ipString) ' ' <> "(" <> show w32 <> ")"
Just (Known F.Bool) ->
forM_ (LBS.chunkBy 1 (segment ^. the @"payload")) $ \bs -> do
let w :: Bool = G.runGet G.get (LBS.take 1 (bs <> LBS.replicate 1 0))
liftIO $ IO.hPrint hOut w
-- WARNING: Don't put a true catch-all (_ -> ...) case here
-- it means we miss this function when new formats get added.
Just (Known F.Binary) -> catchAll
Just (Known F.Char) -> catchAll
Just (Known (F.Repeat _ _)) -> catchAll
Just (Unknown _) -> catchAll
Nothing -> catchAll
where
catchAll = forM_ (zip (LBS.chunkBy 16 (segment ^. the @"payload")) [0 :: Int, 16..]) $ \(bs, j) -> do
let bytes = mconcat (intersperse " " (reverse . take 2 . reverse . ('0':) . flip showHex "" <$> LBS.unpack bs))
liftIO $ IO.hPutStr hOut $ reverse $ take 8 $ reverse $ ("0000000" ++) $ showHex j ""
liftIO $ IO.hPutStr hOut " "
liftIO $ IO.hPutStr hOut $ bytes <> replicate (47 - length bytes) ' '
liftIO $ IO.hPutStr hOut " "
liftIO $ IO.hPutStr hOut $ (\c -> if isPrint c then c else '.') <$> LBSC.unpack bs
liftIO $ IO.hPutStrLn hOut ""