Guest User

Untitled

a guest
Sep 25th, 2015
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE OverloadedStrings #-}
  2. module ASCII85 where
  3. import Data.ByteString (ByteString, pack, unpack, concat)
  4. import Data.Word (Word8)
  5. import Data.Char (digitToInt, chr, ord, isSeparator, intToDigit)
  6. import Data.List.Split (chunksOf, splitWhen)
  7. import Data.List (intercalate)
  8. import Numeric (showIntAtBase)
  9.  
  10. binStringToInt :: String -> Int
  11. binStringToInt = foldl (\ accu x -> accu * 2 + digitToInt x) 0
  12.  
  13. intToFixedBinString :: Int -> Int -> String
  14. intToFixedBinString n bitcount = extraPadding ++ binstr
  15.   where binstr = showIntAtBase 2 intToDigit n ""
  16.         extraPadding = take (bitcount - length binstr) $ repeat ('0')
  17.        
  18. wordToBinString :: Word8 -> String
  19. wordToBinString word = intToFixedBinString (fromIntegral $ toInteger word) 8
  20.  
  21. modsForIntTo85 :: Int -> Int -> [Word8] -> [Word8]
  22. modsForIntTo85 _ (-1) res = reverse res
  23. modsForIntTo85 n left res = modsForIntTo85 (n `div` 85) (left - 1) (res ++ [newmod])
  24.   where newmod = fromIntegral $ toInteger (n `mod` 85)
  25.  
  26. chunkToAscii85 :: [Word8] -> [Word8]
  27. chunkToAscii85 [0, 0, 0, 0] = [122]
  28. chunkToAscii85 chunk = ascii85Chunk
  29.   where fullChunk = chunk ++ take (4 - length chunk) (repeat 0)
  30.         fullChunkAsBinString = foldr (++) "" (map wordToBinString fullChunk)
  31.         fullChunkAsInt = binStringToInt fullChunkAsBinString
  32.         ascii85Chunk = take (length chunk + 1) $ map (+33) (modsForIntTo85 fullChunkAsInt 4 [])
  33.  
  34. toAscii85 :: ByteString -> ByteString
  35. toAscii85 bytes = Data.ByteString.concat [prefix, ascii85Data, suffix]
  36.   where prefix = "<~"
  37.         bytesInChunks = chunksOf 4 (unpack bytes)
  38.         ascii85Data = pack $ foldl (++) [] $ map chunkToAscii85 bytesInChunks
  39.         suffix = "~>"
  40.  
  41. wordsBackToInt :: [Word8] -> Int -> Int
  42. wordsBackToInt [] _ = 0
  43. wordsBackToInt (w:rest) cnt = ((fromIntegral $ toInteger w) - 33) * (85^cnt) + wordsBackToInt rest (cnt - 1)
  44.  
  45. binStringToWord :: String -> Word8
  46. binStringToWord = foldl (\ accu x -> accu * 2 + (fromInteger $ toInteger (digitToInt x))) 0
  47.  
  48. decodeChunk :: [Word8] -> [Word8]
  49. decodeChunk chunk = decodedChunk
  50.   where fullChunk = chunk ++ take (5 - length chunk) (repeat 117)
  51.         fullChunkAsInt = wordsBackToInt fullChunk 4
  52.         fullChunkAsBinaryComponents = chunksOf 8 $ intToFixedBinString fullChunkAsInt 32
  53.         characters = map binStringToWord fullChunkAsBinaryComponents
  54.         decodedChunk = take (length chunk - 1) characters
  55.  
  56. fromAscii85 :: ByteString -> ByteString
  57. fromAscii85 bytes = pack $ foldl (++) [] $ map decodeChunk (chunksOf 5 bytesWithNoZeds)
  58.   where unpackedBytes = unpack bytes
  59.         isValidChar chr = chr >= 33 && (chr <= 117 || chr == 122)
  60.         cleanBytes = filter isValidChar $ take (length unpackedBytes - 4) (drop 2 unpackedBytes)
  61.         longhandNulls = take 5 $ repeat 33
  62.         bytesWithNoZeds = intercalate longhandNulls $ splitWhen (==122) cleanBytes
Advertisement
Add Comment
Please, Sign In to add comment