{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE Safe #-}
module StringUtils where
import qualified Data.ByteString as BS
import Data.ByteString.Builder
import qualified Data.ByteString.Char8 as BSC
import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString.Lazy.Char8 as BSLC
import Data.Semigroup ((<>))
import Numeric
import MiscUtils
class Paddable a
where
pad :: Char -> Int -> a -> a
instance Paddable String
where
pad char len str = let
remainder = mod (len - Prelude.length str) len
extra = replicate remainder char
in str ++ extra
instance Paddable BS.ByteString
where
pad char len str = let
remainder = mod (len - BS.length str) len
extra = replicate remainder char
in str <> BSC.pack extra
class HexStringable a where
hexStringToByteString :: a -> BS.ByteString
byteStringToHexString :: BS.ByteString -> a
stringToHexString :: String -> a
instance HexStringable BS.ByteString where
hexStringToByteString s = BSLC.toStrict . toLazyByteString $ builder
where
builder = foldr go (byteString BS.empty) $ BSC.unpack <$> chunk 2 s
go a builder' = newbuilder <> builder'
where
newbuilder = word8 . fst . head . readHex . take 2 $ a
byteStringToHexString = BSL.toStrict . toLazyByteString . byteStringHex
stringToHexString = byteStringToHexString . BSC.pack
instance HexStringable BSL.ByteString where
hexStringToByteString s = BSLC.toStrict . toLazyByteString $ builder
where
strict = BSL.toStrict s
builder = foldr go (byteString BS.empty) $ BSC.unpack <$> chunk 2 strict
go a builder' = newbuilder <> builder'
where
newbuilder = word8 . fst . head . readHex . take 2 $ a
byteStringToHexString = toLazyByteString . byteStringHex
stringToHexString = byteStringToHexString . BSC.pack
instance HexStringable String where
hexStringToByteString s = BSL.toStrict . toLazyByteString $ builder
where
builder = foldr go (byteString BS.empty) $ chunk 2 s
go a builder' = newbuilder <> builder'
where
newbuilder = word8 . fst . head . readHex . take 2 $ a
byteStringToHexString = BSLC.unpack . toLazyByteString . byteStringHex
stringToHexString = BSLC.unpack . toLazyByteString . byteStringHex . BSC.pack
bsRange :: BS.ByteString -> Int -> Int -> BS.ByteString
bsRange source offset len = (BS.take len . BS.drop offset) source
bsReplace :: BS.ByteString -> Int -> BS.ByteString -> BS.ByteString
bsReplace source offset new
| BS.length result /= BS.length source = error errorMsg
| otherwise = result
where
(initial, initialRest) = BS.splitAt offset source
final = BS.drop (BS.length new) initialRest
result = BS.append (BS.append initial new) final
sourceLength = BS.length source
newLength = BS.length new
errorMsg = "Source length " ++ show sourceLength
++ "; replacement length: " ++ show newLength
++ " ...looks like source is shorter than required"