sgf-0.1.3.2: Data/SGF/Parse/Encodings.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE InstanceSigs #-}
module Data.SGF.Parse.Encodings
( guessEncoding
, decodeWordStringExplicit
) where
import Control.Applicative (Applicative(..))
import Control.Exception.Extensible
import Control.Monad (ap, liftM)
import Control.Monad.State
import Control.Throws
import Data.Encoding
import Data.Word
type MyIHateGHC = MyEither DecodingException (String, [Word8])
newtype MyEither a b =
MyEither (Either a b)
deriving (Throws a)
instance Functor (MyEither a) where
fmap = liftM
instance Applicative (MyEither a) where
pure :: a2 -> MyEither a1 a2
pure x = return x -- note that an eta reduced version of this trips the type checker for non-canonical "pure = return"
(<*>) :: MyEither a1 (a2 -> b) -> MyEither a1 a2 -> MyEither a1 b
(<*>) = ap
instance Monad (MyEither a) where
(MyEither (Right x)) >>= f = f x
(MyEither (Left x)) >>= f = MyEither (Left x)
instance ByteSource (StateT [Word8] (MyEither DecodingException)) where
sourceEmpty = gets null
fetchWord8 = do
s <- get
case s of
[] -> throwException UnexpectedEnd
c:cs -> put cs >> return c
fetchAhead m = do
s <- get
v <- m
put s
return v
-- some ones that we know satisfy our invariant (see SGF.Parse.Raw)
encodings = map encodingFromString ["latin1", "utf-8", "ascii"]
guess ws encoding =
case runStateT (decode encoding) ws :: MyIHateGHC of
(MyEither (Right (s, []))) ->
encodingFromStringExplicit s == Just encoding
_ -> False
-- |
-- Try decoding the given word string with each of the known-good encodings to
-- see if the decoded name names the encoding used to decode. It should be
-- impossible for this to return a list with more than one guess.
guessEncoding :: [Word8] -> [DynEncoding]
guessEncoding ws = filter (guess ws) encodings
-- |
-- A simple wrapper around the encoding package's 'decode' function.
decodeWordStringExplicit ::
Encoding e => e -> [Word8] -> Either DecodingException String
decodeWordStringExplicit e ws =
case runStateT (decode e) ws :: MyIHateGHC of
(MyEither (Right (s, _))) -> Right s
(MyEither (Left ex)) -> Left ex