    -- | Base-level decode function for OSC packets.
    --   For ordinary use see 'Sound.OSC.Coding.Decode.Binary'.
    module Sound.OSC.Coding.Decode.Base (decodeMessage
                                        ,decodeBundle
                                        ,decodePacket) where

    import Data.Binary {- base -}
    import qualified Data.ByteString.Char8 as C {- bytestring -}
    import qualified Data.ByteString.Lazy as B {- bytestring -}
    import Data.List {- base -}
    import Data.Maybe {- base -}

    import Sound.OSC.Coding.Byte {- hosc -}
    import Sound.OSC.Datum {- hosc -}
    import Sound.OSC.Packet {- hosc -}
    import Sound.OSC.Time {- hosc -}

    -- The plain byte count of an OSC value.
    size :: Datum_Type -> B.ByteString -> Int
    size :: Datum_Type -> ByteString -> Int
    size ty :: Datum_Type
    ty b :: ByteString
    b =
        case Datum_Type
    ty of
          'i' -> 4
          'f' -> 4
          'd' -> 8
          't' -> 8 -- timetag
          'm' -> 4 -- MIDI message
          's' -> Int64 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Int64 -> Maybe Int64 -> Int64
    forall a. a -> Maybe a -> a
    fromMaybe
                               ([Datum_Type] -> Int64
    forall a. HasCallStack => [Datum_Type] -> a
    error ("size: no terminating zero: " [Datum_Type] -> [Datum_Type] -> [Datum_Type]
    forall a. [a] -> [a] -> [a]
    ++ ByteString -> [Datum_Type]
    forall a. Show a => a -> [Datum_Type]
    show ByteString
    b))
                               (Word8 -> ByteString -> Maybe Int64
    B.elemIndex 0 ByteString
    b))
          'b' -> ByteString -> Int
    decode_i32 (Int64 -> ByteString -> ByteString
    B.take 4 ByteString
    b)
          _ -> [Datum_Type] -> Int
    forall a. HasCallStack => [Datum_Type] -> a
    error "size: illegal type"

    -- The storage byte count of an OSC value.
    storage :: Datum_Type -> B.ByteString -> Int
    storage :: Datum_Type -> ByteString -> Int
    storage ty :: Datum_Type
    ty b :: ByteString
    b =
        case Datum_Type
    ty of
          's' -> let n :: Int
    n = Datum_Type -> ByteString -> Int
    size 's' ByteString
    b Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + 1 in Int
    n Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int -> Int
    forall i. (Num i, Bits i) => i -> i
    align Int
    n
          'b' -> let n :: Int
    n = Datum_Type -> ByteString -> Int
    size 'b' ByteString
    b in Int
    n Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int -> Int
    forall i. (Num i, Bits i) => i -> i
    align Int
    n Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + 4
          _ -> Datum_Type -> ByteString -> Int
    size Datum_Type
    ty ByteString
    B.empty

    -- Decode an OSC datum
    decode_datum :: Datum_Type -> B.ByteString -> Datum
    decode_datum :: Datum_Type -> ByteString -> Datum
    decode_datum ty :: Datum_Type
    ty b :: ByteString
    b =
        case Datum_Type
    ty of
          'i' -> Int32 -> Datum
    Int32 (ByteString -> Int32
    forall a. Binary a => ByteString -> a
    decode ByteString
    b)
          'h' -> Int64 -> Datum
    Int64 (ByteString -> Int64
    forall a. Binary a => ByteString -> a
    decode ByteString
    b)
          'f' -> Float -> Datum
    Float (ByteString -> Float
    decode_f32 ByteString
    b)
          'd' -> Double -> Datum
    Double (ByteString -> Double
    decode_f64 ByteString
    b)
          's' -> ASCII -> Datum
    ASCII_String (ByteString -> ASCII
    decode_str (Int -> ByteString -> ByteString
    b_take (Datum_Type -> ByteString -> Int
    size 's' ByteString
    b) ByteString
    b))
          'b' -> ByteString -> Datum
    Blob (Int -> ByteString -> ByteString
    b_take (Datum_Type -> ByteString -> Int
    size 'b' ByteString
    b) (Int64 -> ByteString -> ByteString
    B.drop 4 ByteString
    b))
          't' -> Double -> Datum
    TimeStamp (NTP64 -> Double
    forall n. Fractional n => NTP64 -> n
    ntpi_to_ntpr (ByteString -> NTP64
    decode_u64 ByteString
    b))
          'm' -> let [b0 :: Word8
    b0,b1 :: Word8
    b1,b2 :: Word8
    b2,b3 :: Word8
    b3] = ByteString -> [Word8]
    B.unpack (Int64 -> ByteString -> ByteString
    B.take 4 ByteString
    b)
                 in (Word8, Word8, Word8, Word8) -> Datum
    midi (Word8
    b0,Word8
    b1,Word8
    b2,Word8
    b3)
          _ -> [Datum_Type] -> Datum
    forall a. HasCallStack => [Datum_Type] -> a
    error ("decode_datum: illegal type (" [Datum_Type] -> [Datum_Type] -> [Datum_Type]
    forall a. [a] -> [a] -> [a]
    ++ [Datum_Type
    ty] [Datum_Type] -> [Datum_Type] -> [Datum_Type]
    forall a. [a] -> [a] -> [a]
    ++ ")")

    -- Decode a sequence of OSC datum given a type descriptor string.
    decode_datum_seq :: ASCII -> B.ByteString -> [Datum]
    decode_datum_seq :: ASCII -> ByteString -> [Datum]
    decode_datum_seq cs :: ASCII
    cs b :: ByteString
    b =
        let swap :: (b, a) -> (a, b)
    swap (x :: b
    x,y :: a
    y) = (a
    y,b
    x)
            cs' :: [Datum_Type]
    cs' = ASCII -> [Datum_Type]
    C.unpack ASCII
    cs
            f :: ByteString -> Datum_Type -> (ByteString, ByteString)
    f b' :: ByteString
    b' c :: Datum_Type
    c = (ByteString, ByteString) -> (ByteString, ByteString)
    forall b a. (b, a) -> (a, b)
    swap (Int64 -> ByteString -> (ByteString, ByteString)
    B.splitAt (Int -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Datum_Type -> ByteString -> Int
    storage Datum_Type
    c ByteString
    b')) ByteString
    b')
        in (Datum_Type -> ByteString -> Datum)
    -> [Datum_Type] -> [ByteString] -> [Datum]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith Datum_Type -> ByteString -> Datum
    decode_datum [Datum_Type]
    cs' ((ByteString, [ByteString]) -> [ByteString]
    forall a b. (a, b) -> b
    snd ((ByteString -> Datum_Type -> (ByteString, ByteString))
    -> ByteString -> [Datum_Type] -> (ByteString, [ByteString])
    forall (t :: * -> *) a b c.
    Traversable t =>
    (a -> b -> (a, c)) -> a -> t b -> (a, t c)
    mapAccumL ByteString -> Datum_Type -> (ByteString, ByteString)
    f ByteString
    b [Datum_Type]
    cs'))

    -- | Decode an OSC 'Message'.
    decodeMessage :: B.ByteString -> Message
    decodeMessage :: ByteString -> Message
    decodeMessage b :: ByteString
    b =
        let n :: Int
    n = Datum_Type -> ByteString -> Int
    storage 's' ByteString
    b
            (ASCII_String cmd :: ASCII
    cmd) = Datum_Type -> ByteString -> Datum
    decode_datum 's' ByteString
    b
            m :: Int
    m = Datum_Type -> ByteString -> Int
    storage 's' (Int -> ByteString -> ByteString
    b_drop Int
    n ByteString
    b)
            (ASCII_String dsc :: ASCII
    dsc) = Datum_Type -> ByteString -> Datum
    decode_datum 's' (Int -> ByteString -> ByteString
    b_drop Int
    n ByteString
    b)
            arg :: [Datum]
    arg = ASCII -> ByteString -> [Datum]
    decode_datum_seq (ASCII -> ASCII
    descriptor_tags ASCII
    dsc) (Int -> ByteString -> ByteString
    b_drop (Int
    n Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    m) ByteString
    b)
        in [Datum_Type] -> [Datum] -> Message
    Message (ASCII -> [Datum_Type]
    C.unpack ASCII
    cmd) [Datum]
    arg

    -- Decode a sequence of OSC messages, each one headed by its length
    decode_message_seq :: B.ByteString -> [Message]
    decode_message_seq :: ByteString -> [Message]
    decode_message_seq b :: ByteString
    b =
        let s :: Int
    s = ByteString -> Int
    decode_i32 ByteString
    b
            m :: Message
    m = ByteString -> Message
    decodeMessage (Int -> ByteString -> ByteString
    b_drop 4 ByteString
    b)
            nxt :: [Message]
    nxt = ByteString -> [Message]
    decode_message_seq (Int -> ByteString -> ByteString
    b_drop (4Int -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    s) ByteString
    b)
        in if ByteString -> Int64
    B.length ByteString
    b Int64 -> Int64 -> Bool
    forall a. Eq a => a -> a -> Bool
    == 0 then [] else Message
    mMessage -> [Message] -> [Message]
    forall a. a -> [a] -> [a]
    :[Message]
    nxt

    -- | Decode an OSC 'Bundle'.
    decodeBundle :: B.ByteString -> Bundle
    decodeBundle :: ByteString -> Bundle
    decodeBundle b :: ByteString
    b =
        let h :: Int
    h = Datum_Type -> ByteString -> Int
    storage 's' ByteString
    b -- header (should be '#bundle')
            t :: Int
    t = Datum_Type -> ByteString -> Int
    storage 't' (Int -> ByteString -> ByteString
    b_drop Int
    h ByteString
    b) -- time tag
            (TimeStamp timeStamp :: Double
    timeStamp) = Datum_Type -> ByteString -> Datum
    decode_datum 't' (Int -> ByteString -> ByteString
    b_drop Int
    h ByteString
    b)
            ms :: [Message]
    ms = ByteString -> [Message]
    decode_message_seq (Int -> ByteString -> ByteString
    b_drop (Int
    hInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    t) ByteString
    b)
        in Double -> [Message] -> Bundle
    Bundle Double
    timeStamp [Message]
    ms

    -- | Decode an OSC 'Packet'.
    --
    -- > let b = B.pack [47,103,95,102,114,101,101,0,44,105,0,0,0,0,0,0]
    -- > in decodePacket b == Message "/g_free" [Int 0]
    decodePacket :: B.ByteString -> Packet
    decodePacket :: ByteString -> Packet
    decodePacket b :: ByteString
    b =
        if ByteString
    bundleHeader ByteString -> ByteString -> Bool
    `B.isPrefixOf` ByteString
    b
        then Bundle -> Packet
    Packet_Bundle (ByteString -> Bundle
    decodeBundle ByteString
    b)
        else Message -> Packet
    Packet_Message (ByteString -> Message
    decodeMessage ByteString
    b)

    -- * UTIL

    -- | 'B.take' with 'Int' count.
    b_take :: Int -> B.ByteString -> B.ByteString
    b_take :: Int -> ByteString -> ByteString
    b_take = Int64 -> ByteString -> ByteString
    B.take (Int64 -> ByteString -> ByteString)
    -> (Int -> Int64) -> Int -> ByteString -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral

    -- | 'B.drop' with 'Int' count.
    b_drop :: Int -> B.ByteString -> B.ByteString
    b_drop :: Int -> ByteString -> ByteString
    b_drop = Int64 -> ByteString -> ByteString
    B.drop (Int64 -> ByteString -> ByteString)
    -> (Int -> Int64) -> Int -> ByteString -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral