module Data.Text.Punycode.Decode (decode) where
import qualified Data.ByteString as BS
import Data.Char
import Data.Serialize hiding (decode)
import Data.Word
import Data.Text.Punycode.Shared
decode :: BS.ByteString -> String
decode input = let Right out = runGet (inner2 initial_n 0 initial_bias before) after in out
where (before, after)
| BS.any f input = (init $ map (chr . fromIntegral) $ BS.unpack b1, a1)
| otherwise = ("", input)
f = (== (fromIntegral $ ord '-'))
(b1, a1) = BS.breakEnd f input
inner2 :: Int -> Int -> Int -> String -> Get String
inner2 n oldi bias output = do
b <- isEmpty
helper b
where helper False = do
i <- inner base 1 oldi bias
helper' i
where helper' i = inner2 n' (i' + 1) bias' output'
where bias' = adapt (i oldi) (length output + 1) (oldi == 0)
n' = n + i `div` (length output + 1)
i' = i `mod` (length output + 1)
output' = insertInto output n' i'
helper True = return output
inner :: Int -> Int -> Int -> Int -> Get Int
inner k w i bias = do
word8 <- getWord8
helper $ word8ToDigit word8
where helper digit
| digit < t = return i'
| otherwise = inner (k + base) w' i' bias
where w' = w * (base t)
i' = i + digit * w
t
| k <= bias + tmin = tmin
| k >= bias + tmax = tmax
| otherwise = k bias
insertInto :: String -> Int -> Int -> String
insertInto input n i = take i input ++ [chr n] ++ drop i input
word8ToDigit :: Word8 -> Int
word8ToDigit = helper . fromIntegral
where helper word8
| word8 >= ord 'a' && word8 <= ord 'z' = word8 (ord 'a')
| otherwise = 26 + word8 (ord '0')