{-# LANGUAGE TemplateHaskell #-}
module Net.DNSBase.Domain
(
Domain(RootDomain)
, DnsTriple(..)
, Host
, fromHost
, toHost
, Mbox
, fromMbox
, toMbox
, dnLit
, mbLit
, dnLit8
, mbLit8
, wireToDomain
, decodePresentationDomain
, decodePresentationMbox
, Domain8Err(..)
, makeDomain8
, makeDomain8Str
, makeMbox8
, makeMbox8Str
, canonicalise
, appendDomain
, consDomain
, unconsDomain
, labelCount
, fromLabels
, toLabels
, revLabels
, commonSuffix
, mbWireForm
, shortBytes
, wireBytes
, isLDHName
, isLDHLabel
, compareWireHost
, equalWireHost
, canonicalNameOrder
, sortDomains
) where
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C8
import qualified Data.ByteString.Unsafe as BU
import qualified Data.Char as Ch
import qualified Language.Haskell.TH.Syntax as TH
import Control.Monad.ST (ST, runST)
import Data.Primitive.ByteArray
( MutableByteArray
, copyMutableByteArray
, newByteArray
, unsafeFreezeByteArray
, writeByteArray
)
import Net.DNSBase.Internal.Domain
import Net.DNSBase.Internal.Util
data Domain8Err
= D8LabelTooLong
| D8WireTooLong
| D8BadEscape
| D8EmptyLabel
| D8Non8Bit
| D8Non7Bit
deriving (Domain8Err -> Domain8Err -> Bool
(Domain8Err -> Domain8Err -> Bool)
-> (Domain8Err -> Domain8Err -> Bool) -> Eq Domain8Err
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Domain8Err -> Domain8Err -> Bool
== :: Domain8Err -> Domain8Err -> Bool
$c/= :: Domain8Err -> Domain8Err -> Bool
/= :: Domain8Err -> Domain8Err -> Bool
Eq, Int -> Domain8Err -> ShowS
[Domain8Err] -> ShowS
Domain8Err -> String
(Int -> Domain8Err -> ShowS)
-> (Domain8Err -> String)
-> ([Domain8Err] -> ShowS)
-> Show Domain8Err
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Domain8Err -> ShowS
showsPrec :: Int -> Domain8Err -> ShowS
$cshow :: Domain8Err -> String
show :: Domain8Err -> String
$cshowList :: [Domain8Err] -> ShowS
showList :: [Domain8Err] -> ShowS
Show)
maxWireLen :: Int
maxWireLen :: Int
maxWireLen = Int
255
maxLabelLen :: Int
maxLabelLen :: Int
maxLabelLen = Int
63
outBufSize :: Int
outBufSize :: Int
outBufSize = Int
maxWireLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
makeDomain8 :: ByteString -> Either Domain8Err Domain
makeDomain8 :: ByteString -> Either Domain8Err Domain
makeDomain8 = (ShortByteString -> Domain)
-> Either Domain8Err ShortByteString -> Either Domain8Err Domain
forall a b. (a -> b) -> Either Domain8Err a -> Either Domain8Err b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ShortByteString -> Domain
Domain_ (Either Domain8Err ShortByteString -> Either Domain8Err Domain)
-> (ByteString -> Either Domain8Err ShortByteString)
-> ByteString
-> Either Domain8Err Domain
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either Domain8Err ShortByteString
parseDomain8Wire
makeMbox8 :: ByteString -> Either Domain8Err Domain
makeMbox8 :: ByteString -> Either Domain8Err Domain
makeMbox8 = (ShortByteString -> Domain)
-> Either Domain8Err ShortByteString -> Either Domain8Err Domain
forall a b. (a -> b) -> Either Domain8Err a -> Either Domain8Err b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ShortByteString -> Domain
Domain_ (Either Domain8Err ShortByteString -> Either Domain8Err Domain)
-> (ByteString -> Either Domain8Err ShortByteString)
-> ByteString
-> Either Domain8Err Domain
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either Domain8Err ShortByteString
parseMbox8Wire
makeDomain8Str :: String -> Either Domain8Err Domain
makeDomain8Str :: String -> Either Domain8Err Domain
makeDomain8Str = String -> Either Domain8Err ByteString
safePack (String -> Either Domain8Err ByteString)
-> (ByteString -> Either Domain8Err Domain)
-> String
-> Either Domain8Err Domain
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> (ShortByteString -> Domain)
-> Either Domain8Err ShortByteString -> Either Domain8Err Domain
forall a b. (a -> b) -> Either Domain8Err a -> Either Domain8Err b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ShortByteString -> Domain
Domain_ (Either Domain8Err ShortByteString -> Either Domain8Err Domain)
-> (ByteString -> Either Domain8Err ShortByteString)
-> ByteString
-> Either Domain8Err Domain
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either Domain8Err ShortByteString
parseDomain8Wire
makeMbox8Str :: String -> Either Domain8Err Domain
makeMbox8Str :: String -> Either Domain8Err Domain
makeMbox8Str = String -> Either Domain8Err ByteString
safePack (String -> Either Domain8Err ByteString)
-> (ByteString -> Either Domain8Err Domain)
-> String
-> Either Domain8Err Domain
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> (ShortByteString -> Domain)
-> Either Domain8Err ShortByteString -> Either Domain8Err Domain
forall a b. (a -> b) -> Either Domain8Err a -> Either Domain8Err b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ShortByteString -> Domain
Domain_ (Either Domain8Err ShortByteString -> Either Domain8Err Domain)
-> (ByteString -> Either Domain8Err ShortByteString)
-> ByteString
-> Either Domain8Err Domain
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either Domain8Err ShortByteString
parseMbox8Wire
parseDomain8Wire :: ByteString -> Either Domain8Err ShortByteString
parseDomain8Wire :: ByteString -> Either Domain8Err ShortByteString
parseDomain8Wire !ByteString
bs = (forall s. ST s (Either Domain8Err ShortByteString))
-> Either Domain8Err ShortByteString
forall a. (forall s. ST s a) -> a
runST do
outBuf <- Int -> ST s (MutableByteArray (PrimState (ST s)))
forall (m :: * -> *).
PrimMonad m =>
Int -> m (MutableByteArray (PrimState m))
newByteArray Int
outBufSize
let !inEnd = ByteString -> Int
B.length ByteString
bs
res <- domainDriver bs inEnd outBuf 0 0 1
finalise outBuf res
parseMbox8Wire :: ByteString -> Either Domain8Err ShortByteString
parseMbox8Wire :: ByteString -> Either Domain8Err ShortByteString
parseMbox8Wire !ByteString
bs =
let !inEnd :: Int
inEnd = ByteString -> Int
B.length ByteString
bs
in case ByteString -> Int -> Int -> Maybe Int
findAt8 ByteString
bs Int
0 Int
inEnd of
Maybe Int
Nothing -> ByteString -> Either Domain8Err ShortByteString
parseDomain8Wire ByteString
bs
Just Int
sepAt -> (forall s. ST s (Either Domain8Err ShortByteString))
-> Either Domain8Err ShortByteString
forall a. (forall s. ST s a) -> a
runST do
outBuf <- Int -> ST s (MutableByteArray (PrimState (ST s)))
forall (m :: * -> *).
PrimMonad m =>
Int -> m (MutableByteArray (PrimState m))
newByteArray Int
outBufSize
res <- mboxDriver bs inEnd outBuf sepAt
finalise outBuf res
dnLit8 :: forall m. (TH.Quote m, MonadFail m) => String -> TH.Code m Domain
dnLit8 :: forall (m :: * -> *).
(Quote m, MonadFail m) =>
String -> Code m Domain
dnLit8 String
s = m (Code m Domain) -> Code m Domain
forall (m :: * -> *) a. Monad m => m (Code m a) -> Code m a
TH.joinCode case String -> Either Domain8Err Domain
makeDomain8Str String
s of
Left Domain8Err
why -> String -> m (Code m Domain)
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> m (Code m Domain)) -> String -> m (Code m Domain)
forall a b. (a -> b) -> a -> b
$ String
"Invalid literal domain " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. Show a => a -> String
show String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Domain8Err -> String
forall a. Show a => a -> String
show Domain8Err
why
Right Domain
dn -> Code m Domain -> m (Code m Domain)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain -> Code m Domain
forall t (m :: * -> *). (Lift t, Quote m) => t -> Code m t
forall (m :: * -> *). Quote m => Domain -> Code m Domain
TH.liftTyped Domain
dn)
mbLit8 :: forall m. (TH.Quote m, MonadFail m) => String -> TH.Code m Domain
mbLit8 :: forall (m :: * -> *).
(Quote m, MonadFail m) =>
String -> Code m Domain
mbLit8 String
s = m (Code m Domain) -> Code m Domain
forall (m :: * -> *) a. Monad m => m (Code m a) -> Code m a
TH.joinCode case String -> Either Domain8Err Domain
makeMbox8Str String
s of
Left Domain8Err
why -> String -> m (Code m Domain)
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> m (Code m Domain)) -> String -> m (Code m Domain)
forall a b. (a -> b) -> a -> b
$ String
"Invalid mailbox literal " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. Show a => a -> String
show String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Domain8Err -> String
forall a. Show a => a -> String
show Domain8Err
why
Right Domain
dn -> Code m Domain -> m (Code m Domain)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain -> Code m Domain
forall t (m :: * -> *). (Lift t, Quote m) => t -> Code m t
forall (m :: * -> *). Quote m => Domain -> Code m Domain
TH.liftTyped Domain
dn)
domainDriver
:: forall s
. ByteString
-> Int
-> MutableByteArray s
-> Int
-> Int
-> Int
-> ST s (Either Domain8Err Int)
domainDriver :: forall s.
ByteString
-> Int
-> MutableByteArray s
-> Int
-> Int
-> Int
-> ST s (Either Domain8Err Int)
domainDriver !ByteString
bs !Int
inEnd !MutableByteArray s
outBuf !Int
startLStart = Int -> Int -> Int -> ST s (Either Domain8Err Int)
go Int
startLStart
where
go :: Int -> Int -> Int -> ST s (Either Domain8Err Int)
go :: Int -> Int -> Int -> ST s (Either Domain8Err Int)
go !Int
lStart !Int
iPos !Int
oPos
| Int
iPos Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
inEnd = Int -> Int -> ST s (Either Domain8Err Int)
endOfInput Int
lStart Int
oPos
| Bool
otherwise =
let !b :: Word8
b = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
iPos
in if | Word8
b Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x5C -> Int -> Int -> Int -> ST s (Either Domain8Err Int)
handleEsc Int
lStart Int
iPos Int
oPos
| Word8
b Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x2E -> Int -> Int -> Int -> ST s (Either Domain8Err Int)
handleDot Int
lStart Int
iPos Int
oPos
| Bool
otherwise -> Word8 -> Int -> Int -> Int -> ST s (Either Domain8Err Int)
appendByte Word8
b Int
lStart (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
oPos
appendByte :: Word8 -> Int -> Int -> Int -> ST s (Either Domain8Err Int)
appendByte :: Word8 -> Int -> Int -> Int -> ST s (Either Domain8Err Int)
appendByte !Word8
b !Int
lStart !Int
iPos !Int
oPos
| Int
oPos Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
lStart Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxLabelLen = Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8LabelTooLong)
| Int
oPos Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
maxWireLen = Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8WireTooLong)
| Bool
otherwise = do
MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
outBuf Int
oPos Word8
b
Int -> Int -> Int -> ST s (Either Domain8Err Int)
go Int
lStart Int
iPos (Int
oPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
handleEsc :: Int -> Int -> Int -> ST s (Either Domain8Err Int)
handleEsc :: Int -> Int -> Int -> ST s (Either Domain8Err Int)
handleEsc !Int
lStart !Int
iPos !Int
oPos
| Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
inEnd = Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8BadEscape)
| Bool
otherwise =
let !b1 :: Word8
b1 = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
in case Word8 -> Maybe Word8
asciiDigit Word8
b1 of
Maybe Word8
Nothing -> Word8 -> Int -> Int -> Int -> ST s (Either Domain8Err Int)
appendByte Word8
b1 Int
lStart (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) Int
oPos
Just !Word8
v1
| Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
inEnd -> Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8BadEscape)
| Bool
otherwise ->
let !b2 :: Word8
b2 = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
!b3 :: Word8
b3 = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3)
in case (Word8 -> Maybe Word8
asciiDigit Word8
b2, Word8 -> Maybe Word8
asciiDigit Word8
b3) of
(Just Word8
v2, Just Word8
v3)
| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0xFF ->
Word8 -> Int -> Int -> Int -> ST s (Either Domain8Err Int)
appendByte (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n) Int
lStart
(Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4) Int
oPos
| Bool
otherwise -> Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8BadEscape)
where
!n :: Int
n = Int
100 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
v1
Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
10 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
v2
Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
v3 :: Int
(Maybe Word8, Maybe Word8)
_ -> Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8BadEscape)
handleDot :: Int -> Int -> Int -> ST s (Either Domain8Err Int)
handleDot :: Int -> Int -> Int -> ST s (Either Domain8Err Int)
handleDot !Int
lStart !Int
iPos !Int
oPos
| Int
oPos Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
lStart Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 =
if Int
lStart Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
startLStart Bool -> Bool -> Bool
&& Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
inEnd
then Int -> Int -> Int -> ST s (Either Domain8Err Int)
go Int
lStart (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
oPos
else Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8EmptyLabel)
| Bool
otherwise = do
let !labelLen :: Int
labelLen = Int
oPos Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
lStart Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
outBuf Int
lStart (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
labelLen :: Word8)
let !lStart' :: Int
lStart' = Int
oPos
!oPos' :: Int
oPos' = Int
lStart' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
Int -> Int -> Int -> ST s (Either Domain8Err Int)
go Int
lStart' (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
oPos'
endOfInput :: Int -> Int -> ST s (Either Domain8Err Int)
endOfInput :: Int -> Int -> ST s (Either Domain8Err Int)
endOfInput !Int
lStart !Int
oPos
| Int
oPos Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
lStart Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 =
Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Either Domain8Err Int
forall a b. b -> Either a b
Right Int
lStart)
| Bool
otherwise = do
let !labelLen :: Int
labelLen = Int
oPos Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
lStart Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
outBuf Int
lStart (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
labelLen :: Word8)
Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Either Domain8Err Int
forall a b. b -> Either a b
Right Int
oPos)
localpartDriver
:: forall s. ByteString
-> Int
-> MutableByteArray s
-> ST s (Either Domain8Err Int)
localpartDriver :: forall s.
ByteString
-> Int -> MutableByteArray s -> ST s (Either Domain8Err Int)
localpartDriver !ByteString
bs !Int
lpEnd !MutableByteArray s
outBuf = Int -> Int -> ST s (Either Domain8Err Int)
go Int
0 Int
1
where
go :: Int -> Int -> ST s (Either Domain8Err Int)
go :: Int -> Int -> ST s (Either Domain8Err Int)
go !Int
iPos !Int
oPos
| Int
iPos Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
lpEnd = Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Either Domain8Err Int
forall a b. b -> Either a b
Right (Int
oPos Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1))
| Bool
otherwise =
let !b :: Word8
b = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
iPos
in if | Word8
b Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x5C -> Int -> Int -> ST s (Either Domain8Err Int)
handleEsc Int
iPos Int
oPos
| Bool
otherwise -> Word8 -> Int -> Int -> ST s (Either Domain8Err Int)
appendByte Word8
b (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
oPos
appendByte :: Word8 -> Int -> Int -> ST s (Either Domain8Err Int)
appendByte :: Word8 -> Int -> Int -> ST s (Either Domain8Err Int)
appendByte !Word8
b !Int
iPos !Int
oPos
| Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Word8
0x7F = Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8Non7Bit)
| Int
oPos Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxLabelLen = Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8LabelTooLong)
| Bool
otherwise = do
MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
outBuf Int
oPos Word8
b
Int -> Int -> ST s (Either Domain8Err Int)
go Int
iPos (Int
oPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
handleEsc :: Int -> Int -> ST s (Either Domain8Err Int)
handleEsc :: Int -> Int -> ST s (Either Domain8Err Int)
handleEsc !Int
iPos !Int
oPos
| Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
lpEnd = Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8BadEscape)
| Word8
b1 <- ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
, Word8
v1 <- Word8
b1 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30
= if | Word8
v1 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Word8
9 -> Word8 -> Int -> Int -> ST s (Either Domain8Err Int)
appendByte Word8
b1 (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) Int
oPos
| Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
lpEnd -> Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8BadEscape)
| Word8
v2 <- ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30
, Word8
v2 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
9
, Word8
v3 <- ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3) Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30
, Word8
v3 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
9
, !Word8
n <- (Word8
v1 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
* Word8
100 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
v2 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
* Word8
10 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
v3)
-> if | Word8
n Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
0xFF -> Word8 -> Int -> Int -> ST s (Either Domain8Err Int)
appendByte (Word8 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
n) (Int
iPos Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4) Int
oPos
| Bool
otherwise -> Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8BadEscape)
| Bool
otherwise -> Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8BadEscape)
mboxDriver
:: forall s
. ByteString
-> Int
-> MutableByteArray s
-> Int
-> ST s (Either Domain8Err Int)
mboxDriver :: forall s.
ByteString
-> Int -> MutableByteArray s -> Int -> ST s (Either Domain8Err Int)
mboxDriver !ByteString
bs !Int
inEnd !MutableByteArray s
outBuf !Int
sepAt = do
res <- ByteString
-> Int -> MutableByteArray s -> ST s (Either Domain8Err Int)
forall s.
ByteString
-> Int -> MutableByteArray s -> ST s (Either Domain8Err Int)
localpartDriver ByteString
bs Int
sepAt MutableByteArray s
outBuf
case res of
Left Domain8Err
e -> Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
e)
Right Int
lpLen
| Int
lpLen Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 ->
if Int
sepAt Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
inEnd
then Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Either Domain8Err Int
forall a b. b -> Either a b
Right Int
0)
else Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8EmptyLabel)
| Int
lpLen Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
maxLabelLen -> do
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray @Word8 MutableByteArray s
MutableByteArray (PrimState (ST s))
outBuf Int
0 (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lpLen)
let !lpEnd :: Int
lpEnd = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int
lpLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
if Int
sepAt Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
inEnd
then Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Either Domain8Err Int
forall a b. b -> Either a b
Right Int
lpEnd)
else ByteString
-> Int
-> MutableByteArray s
-> Int
-> Int
-> Int
-> ST s (Either Domain8Err Int)
forall s.
ByteString
-> Int
-> MutableByteArray s
-> Int
-> Int
-> Int
-> ST s (Either Domain8Err Int)
domainDriver ByteString
bs Int
inEnd MutableByteArray s
outBuf
Int
lpEnd (Int
sepAt Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
lpEnd Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
| Bool
otherwise -> Either Domain8Err Int -> ST s (Either Domain8Err Int)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err Int
forall a b. a -> Either a b
Left Domain8Err
D8LabelTooLong)
findAt8 :: ByteString -> Int -> Int -> Maybe Int
findAt8 :: ByteString -> Int -> Int -> Maybe Int
findAt8 !ByteString
bs !Int
p0 !Int
inEnd = Int -> Maybe Int
go Int
p0
where
go :: Int -> Maybe Int
go !Int
p
| Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
inEnd = Maybe Int
forall a. Maybe a
Nothing
| Bool
otherwise =
let !b :: Word8
b = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs Int
p
in if | Word8
b Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x40 -> Int -> Maybe Int
forall a. a -> Maybe a
Just Int
p
| Word8
b Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x5C -> Int -> Maybe Int
skipEsc Int
p
| Bool
otherwise -> Int -> Maybe Int
go (Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
skipEsc :: Int -> Maybe Int
skipEsc !Int
p
| Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
inEnd = Maybe Int
forall a. Maybe a
Nothing
| Bool
otherwise =
let !b1 :: Word8
b1 = ByteString -> Int -> Word8
BU.unsafeIndex ByteString
bs (Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
in case Word8 -> Maybe Word8
asciiDigit Word8
b1 of
Just Word8
_ -> Int -> Maybe Int
go (Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4)
Maybe Word8
Nothing -> Int -> Maybe Int
go (Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
finalise
:: forall s
. MutableByteArray s
-> Either Domain8Err Int
-> ST s (Either Domain8Err ShortByteString)
finalise :: forall s.
MutableByteArray s
-> Either Domain8Err Int
-> ST s (Either Domain8Err ShortByteString)
finalise !MutableByteArray s
_ (Left Domain8Err
e) = Either Domain8Err ShortByteString
-> ST s (Either Domain8Err ShortByteString)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err ShortByteString
forall a b. a -> Either a b
Left Domain8Err
e)
finalise !MutableByteArray s
outBuf (Right Int
outLen) =
let !finalLen :: Int
finalLen = Int
outLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
in if Int
finalLen Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxWireLen
then Either Domain8Err ShortByteString
-> ST s (Either Domain8Err ShortByteString)
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Domain8Err -> Either Domain8Err ShortByteString
forall a b. a -> Either a b
Left Domain8Err
D8WireTooLong)
else do
MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
outBuf Int
outLen (Word8
0 :: Word8)
resBA <- Int -> ST s (MutableByteArray (PrimState (ST s)))
forall (m :: * -> *).
PrimMonad m =>
Int -> m (MutableByteArray (PrimState m))
newByteArray Int
finalLen
copyMutableByteArray resBA 0 outBuf 0 finalLen
frozen <- unsafeFreezeByteArray resBA
pure (Right (baToShortByteString frozen))
asciiDigit :: Word8 -> Maybe Word8
asciiDigit :: Word8 -> Maybe Word8
asciiDigit !Word8
w
| Word8
d Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
9 = Word8 -> Maybe Word8
forall a. a -> Maybe a
Just Word8
d
| Bool
otherwise = Maybe Word8
forall a. Maybe a
Nothing
where
!d :: Word8
d = Word8
w Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30
{-# INLINE asciiDigit #-}
safePack :: String -> Either Domain8Err ByteString
safePack :: String -> Either Domain8Err ByteString
safePack String
s
| (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all ((Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0xFF) (Int -> Bool) -> (Char -> Int) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
Ch.ord) String
s = ByteString -> Either Domain8Err ByteString
forall a b. b -> Either a b
Right (String -> ByteString
C8.pack String
s)
| Bool
otherwise = Domain8Err -> Either Domain8Err ByteString
forall a b. a -> Either a b
Left Domain8Err
D8Non8Bit