on e05ab76 help sign in
124 lines 4.2 kB history raw
1{-# LANGUAGE CPP, DeriveDataTypeable #-}
2#if __GLASGOW_HASKELL__ >= 702
3{-# LANGUAGE Trustworthy #-}
4#endif
5-- |
6-- Module : Data.Text.Encoding.Error
7-- Copyright : (c) Bryan O'Sullivan 2009
8--
9-- License : BSD-style
10-- Maintainer : bos@serpentine.com, rtomharper@googlemail.com,
11-- duncan@haskell.org
12-- Stability : experimental
13-- Portability : GHC
14--
15-- Types and functions for dealing with encoding and decoding errors
16-- in Unicode text.
17--
18-- The standard functions for encoding and decoding text are strict,
19-- which is to say that they throw exceptions on invalid input. This
20-- is often unhelpful on real world input, so alternative functions
21-- exist that accept custom handlers for dealing with invalid inputs.
22-- These 'OnError' handlers are normal Haskell functions. You can use
23-- one of the presupplied functions in this module, or you can write a
24-- custom handler of your own.
26module Data.Text.Encoding.Error
27 (
28 -- * Error handling types
29 UnicodeException(..)
30 , OnError
31 , OnDecodeError
32 , OnEncodeError
33 -- * Useful error handling functions
34 , lenientDecode
35 , strictDecode
36 , strictEncode
37 , ignore
38 , replace
39 ) where
41import Control.DeepSeq (NFData (..))
42#if __GLASGOW_HASKELL__ >= 610
43import Control.Exception (Exception, throw)
44#else
45import Control.Exception.Extensible (Exception, throw)
46#endif
47import Data.Typeable (Typeable)
48import Data.Word (Word8)
49import Numeric (showHex)
51-- | Function type for handling a coding error. It is supplied with
52-- two inputs:
53--
54-- * A 'String' that describes the error.
55--
56-- * The input value that caused the error. If the error arose
57-- because the end of input was reached or could not be identified
58-- precisely, this value will be 'Nothing'.
59--
60-- If the handler returns a value wrapped with 'Just', that value will
61-- be used in the output as the replacement for the invalid input. If
62-- it returns 'Nothing', no value will be used in the output.
63--
64-- Should the handler need to abort processing, it should use 'error'
65-- or 'throw' an exception (preferably a 'UnicodeException'). It may
66-- use the description provided to construct a more helpful error
67-- report.
68type OnError a b = String -> Maybe a -> Maybe b
70-- | A handler for a decoding error.
71type OnDecodeError = OnError Word8 Char
73-- | A handler for an encoding error.
74type OnEncodeError = OnError Char Word8
76-- | An exception type for representing Unicode encoding errors.
77data UnicodeException =
78 DecodeError String (Maybe Word8)
79 -- ^ Could not decode a byte sequence because it was invalid under
80 -- the given encoding, or ran out of input in mid-decode.
81 | EncodeError String (Maybe Char)
82 -- ^ Tried to encode a character that could not be represented
83 -- under the given encoding, or ran out of input in mid-encode.
84 deriving (Eq, Typeable)
86showUnicodeException :: UnicodeException -> String
87showUnicodeException (DecodeError desc (Just w))
88 = "Cannot decode byte '\\x" ++ showHex w ("': " ++ desc)
89showUnicodeException (DecodeError desc Nothing)
90 = "Cannot decode input: " ++ desc
91showUnicodeException (EncodeError desc (Just c))
92 = "Cannot encode character '\\x" ++ showHex (fromEnum c) ("': " ++ desc)
93showUnicodeException (EncodeError desc Nothing)
94 = "Cannot encode input: " ++ desc
96instance Show UnicodeException where
97 show = showUnicodeException
99instance Exception UnicodeException
101instance NFData UnicodeException where
102 rnf (DecodeError desc w) = rnf desc `seq` rnf w `seq` ()
103 rnf (EncodeError desc c) = rnf desc `seq` rnf c `seq` ()
105-- | Throw a 'UnicodeException' if decoding fails.
106strictDecode :: OnDecodeError
107strictDecode desc c = throw (DecodeError desc c)
109-- | Replace an invalid input byte with the Unicode replacement
110-- character U+FFFD.
111lenientDecode :: OnDecodeError
112lenientDecode _ _ = Just '\xfffd'
114-- | Throw a 'UnicodeException' if encoding fails.
115strictEncode :: OnEncodeError
116strictEncode desc c = throw (EncodeError desc c)
118-- | Ignore an invalid input, substituting nothing in the output.
119ignore :: OnError a b
120ignore _ _ = Nothing
122-- | Replace an invalid input with a valid output.
123replace :: b -> OnError a b
124replace c _ _ = Just c