{-# LANGUAGE ForeignFunctionInterface #-}

{-|
Description:    Functions providing a means to retrieve the data stored on a disc.

Copyright:      (c) 2018-2021 Sam May
License:        GPL-3.0-or-later
Maintainer:     ag@eitilt.life

Stability:      stable
Portability:    non-portable (requires libcdio)

After obtaining landmarks through "Foreign.Libcdio.Disc" (and likely
"Foreign.Libcdio.Track"), this module provides the functions required to
actually retrive the primary data from the disc.  Some knowledge of its
physical layout is required, which may be determined through
'Foreign.Libcdio.Track.trackFormat'.


= @read.h@

== Types
* @cdio_read_mode_t@                -> 'ReadMode'

    - @CDIO_READ_MODE_M1F1@         -> 'Mode1Form1'
    - @CDIO_READ_MODE_M1F2@         -> 'Mode1Form2'
    - @CDIO_READ_MODE_M2F1@         -> 'Mode2Form1'
    - @CDIO_READ_MODE_M2F2@         -> 'Mode2Form2'

== Symbols
* @cdio_lseek@                      -> 'seek'
* @cdio_read@                       -> 'readBytes'
* @cdio_read_audio_sector@          -> 'readAudioSector'
* @cdio_read_audio_sectors@         -> 'readAudioSectors'
* @cdio_read_data_sectors@          -> 'readDataSectors'
* @cdio_read_mode1_sector@          -> 'readDataModeSector'
* @cdio_read_mode1_sectors@         -> 'readDataModeSectors'
* @cdio_read_mode2_sector@          -> 'readXaModeSector'
* @cdio_read_mode2_sectors@         -> 'readXaModeSectors'
* @cdio_read_sector@                -> 'readSector'
* @cdio_read_sectors@               -> 'readSectors'


= "Sound.Libcdio.Read.Data"
Each of the single-sector @read*@ aliases have been removed for consistency.

* 'ReadMode'                        (removed; unnecessary low-level detail)

* 'readAudioSectors'                -> 'Sound.Libcdio.Read.Data.readAudio'
* 'readBytes'                       -> 'Sound.Libcdio.Read.Data.readRaw' (note that the count is now the number of /sectors/ rather than bytes)
* 'readDataModeSectors'             -> 'Sound.Libcdio.Read.Data.readData'
* 'readDataSectors'                 (removed; unnecessary low-level detail)
* 'readXaModeSectors'               -> 'Sound.Libcdio.Read.Data.readXa'
-}
module Foreign.Libcdio.Read
    ( -- * Types
      ReadMode ( .. )
    , Whence ( .. )
      -- * Functions
      -- ** Raw
    , seek
    , readBytes
      -- ** Sector
    , readSector, readSectors
    , readAudioSector, readAudioSectors
    , readDataSectors
    , readDataModeSector, readDataModeSectors
    , readXaModeSector, readXaModeSectors
    ) where


import qualified Control.Monad as N

import qualified Data.ByteString as BS
import qualified Data.Maybe as Y

import qualified Foreign.C.Types as C
import qualified Foreign.Ptr as C
import qualified Foreign.Storable as S

import qualified Foreign.Marshal.Alloc as M
import qualified Foreign.Marshal.Utils as M

import Foreign.Libcdio.Device
import Foreign.Libcdio.Marshal
import Foreign.Libcdio.Types.Enums
import Foreign.Libcdio.Types.Internal


-- | Reposition the read pointer in the 'Cdio' session for a future call to
-- 'readBytes'.
seek :: Cdio -> Int -> Whence -> IO (Either DriverReturnCode Word)
seek :: Cdio -> Int -> Whence -> IO (Either DriverReturnCode Word)
seek Cdio
c Int
o Whence
w = do
    Maybe CLong
o' <- Cdio -> (Ptr Cdio -> IO CLong) -> IO (Maybe CLong)
forall b. Cdio -> (Ptr Cdio -> IO b) -> IO (Maybe b)
withCdio Cdio
c ((Ptr Cdio -> IO CLong) -> IO (Maybe CLong))
-> (Ptr Cdio -> IO CLong) -> IO (Maybe CLong)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' -> Ptr Cdio -> CLong -> CInt -> IO CLong
seek' Ptr Cdio
c' (Int -> CLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
o) (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CInt) -> Int -> CInt
forall a b. (a -> b) -> a -> b
$ Whence -> Int
forall a. Enum a => a -> Int
fromEnum Whence
w)
    Either DriverReturnCode Word -> IO (Either DriverReturnCode Word)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either DriverReturnCode Word -> IO (Either DriverReturnCode Word))
-> (Either DriverReturnCode CLong -> Either DriverReturnCode Word)
-> Either DriverReturnCode CLong
-> IO (Either DriverReturnCode Word)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CLong -> Word)
-> Either DriverReturnCode CLong -> Either DriverReturnCode Word
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap CLong -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Either DriverReturnCode CLong
 -> IO (Either DriverReturnCode Word))
-> Either DriverReturnCode CLong
-> IO (Either DriverReturnCode Word)
forall a b. (a -> b) -> a -> b
$ Either DriverReturnCode CLong
-> (CLong -> Either DriverReturnCode CLong)
-> Maybe CLong
-> Either DriverReturnCode CLong
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (DriverReturnCode -> Either DriverReturnCode CLong
forall a b. a -> Either a b
Left DriverReturnCode
Uninitialized) CLong -> Either DriverReturnCode CLong
forall a b. (Integral a, Enum b) => a -> Either b a
errorOrInt Maybe CLong
o'

foreign import ccall safe "cdio/compat/read.h cdio_lseek"
  seek' :: C.Ptr Cdio -> C.CLong -> C.CInt -> IO C.CLong


collapseReturnCode :: Maybe DriverReturnCode -> a -> Either DriverReturnCode a
collapseReturnCode :: Maybe DriverReturnCode -> a -> Either DriverReturnCode a
collapseReturnCode (Just DriverReturnCode
Success) a
a = a -> Either DriverReturnCode a
forall a b. b -> Either a b
Right a
a
collapseReturnCode (Just DriverReturnCode
e) a
_ = DriverReturnCode -> Either DriverReturnCode a
forall a b. a -> Either a b
Left DriverReturnCode
e
collapseReturnCode Maybe DriverReturnCode
Nothing a
_ = DriverReturnCode -> Either DriverReturnCode a
forall a b. a -> Either a b
Left DriverReturnCode
Uninitialized


withCdioByteString
    :: Cdio
    -> (C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> IO a)
        -- ^ A foreign function which will read a given number of bytes into a
        -- referenced buffer, potentially returning a numeric error code.  Note
        -- that this marshalling /will/ try to free the inner pointer of the
        -- second argument, so the function should @malloc@ a temporary value
        -- accordingly.
    -> IO (Maybe a, Maybe BS.ByteString)
withCdioByteString :: Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO a)
-> IO (Maybe a, Maybe ByteString)
withCdioByteString Cdio
c Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO a
g = (Ptr (Ptr ()) -> IO (Maybe a, Maybe ByteString))
-> IO (Maybe a, Maybe ByteString)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
M.alloca ((Ptr (Ptr ()) -> IO (Maybe a, Maybe ByteString))
 -> IO (Maybe a, Maybe ByteString))
-> (Ptr (Ptr ()) -> IO (Maybe a, Maybe ByteString))
-> IO (Maybe a, Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr (Ptr ())
bs' -> (Ptr CUInt -> IO (Maybe a, Maybe ByteString))
-> IO (Maybe a, Maybe ByteString)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
M.alloca ((Ptr CUInt -> IO (Maybe a, Maybe ByteString))
 -> IO (Maybe a, Maybe ByteString))
-> (Ptr CUInt -> IO (Maybe a, Maybe ByteString))
-> IO (Maybe a, Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr CUInt
s' -> do
    Maybe a
a <- Cdio -> (Ptr Cdio -> IO a) -> IO (Maybe a)
forall b. Cdio -> (Ptr Cdio -> IO b) -> IO (Maybe b)
withCdio Cdio
c ((Ptr Cdio -> IO a) -> IO (Maybe a))
-> (Ptr Cdio -> IO a) -> IO (Maybe a)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' -> Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO a
g Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s'
    Maybe ByteString
bs <- Ptr (Ptr ()) -> Ptr CUInt -> IO (Maybe ByteString)
forall b a.
(Integral b, Storable b) =>
Ptr (Ptr a) -> Ptr b -> IO (Maybe ByteString)
peekByteStringLen Ptr (Ptr ())
bs' Ptr CUInt
s'
    Ptr ()
p <- Ptr (Ptr ()) -> IO (Ptr ())
forall a. Storable a => Ptr a -> IO a
S.peek Ptr (Ptr ())
bs'
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
N.unless (Ptr ()
p Ptr () -> Ptr () -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr ()
forall a. Ptr a
C.nullPtr) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Ptr () -> IO ()
forall a. Ptr a -> IO ()
M.free Ptr ()
p
    (Maybe a, Maybe ByteString) -> IO (Maybe a, Maybe ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe a
a, Maybe ByteString
bs)

-- | Marshalling function for handling read instructions operating on a given
-- number of whole-sector blocks.
readCdioSectors
    :: Cdio
    -> (C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> IO C.CInt)
    -> IO (Either DriverReturnCode BS.ByteString)
readCdioSectors :: Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
readCdioSectors Cdio
c Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt
f = do
    (Maybe CInt
r, Maybe ByteString
bs) <- Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Maybe CInt, Maybe ByteString)
forall a.
Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO a)
-> IO (Maybe a, Maybe ByteString)
withCdioByteString Cdio
c Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt
f
    Either DriverReturnCode ByteString
-> IO (Either DriverReturnCode ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either DriverReturnCode ByteString
 -> IO (Either DriverReturnCode ByteString))
-> Either DriverReturnCode ByteString
-> IO (Either DriverReturnCode ByteString)
forall a b. (a -> b) -> a -> b
$ Maybe DriverReturnCode
-> ByteString -> Either DriverReturnCode ByteString
forall a. Maybe DriverReturnCode -> a -> Either DriverReturnCode a
collapseReturnCode (Int -> DriverReturnCode
forall a. Enum a => Int -> a
toEnum (Int -> DriverReturnCode)
-> (CInt -> Int) -> CInt -> DriverReturnCode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CInt -> DriverReturnCode) -> Maybe CInt -> Maybe DriverReturnCode
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe CInt
r) (ByteString -> Maybe ByteString -> ByteString
forall a. a -> Maybe a -> a
Y.fromMaybe ByteString
BS.empty Maybe ByteString
bs)


-- | Read a given number of bytes from the disc.  With data of a known
-- structure, use 'readSectors' or similar instead, which /don't/ include the
-- headers and footers described in "Foreign.Libcdio.Sector".
readBytes :: Cdio -> Word -> IO (Maybe BS.ByteString)
readBytes :: Cdio -> Word -> IO (Maybe ByteString)
readBytes Cdio
c Word
l = ((Maybe (), Maybe ByteString) -> Maybe ByteString)
-> IO (Maybe (), Maybe ByteString) -> IO (Maybe ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Maybe (), Maybe ByteString) -> Maybe ByteString
forall a b. (a, b) -> b
snd (IO (Maybe (), Maybe ByteString) -> IO (Maybe ByteString))
-> ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO ())
    -> IO (Maybe (), Maybe ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO ())
-> IO (Maybe ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO ())
-> IO (Maybe (), Maybe ByteString)
forall a.
Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO a)
-> IO (Maybe a, Maybe ByteString)
withCdioByteString Cdio
c ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO ())
 -> IO (Maybe ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO ())
-> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' ->
    Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> CULong -> IO ()
readBytes' Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' (CULong -> IO ()) -> CULong -> IO ()
forall a b. (a -> b) -> a -> b
$ Word -> CULong
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
l

foreign import ccall safe "cdio/compat/read.h read_bytes"
  readBytes' :: C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> C.CULong -> IO ()


-- | Read the data contained in a specific sector from the disc.
readSector :: Cdio -> Lsn -> ReadMode -> IO (Either DriverReturnCode BS.ByteString)
readSector :: Cdio -> Lsn -> ReadMode -> IO (Either DriverReturnCode ByteString)
readSector Cdio
c Lsn
o ReadMode
m = Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
readCdioSectors Cdio
c ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
 -> IO (Either DriverReturnCode ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' ->
    Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> Lsn -> CInt -> IO CInt
readSector' Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' Lsn
o (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CInt) -> Int -> CInt
forall a b. (a -> b) -> a -> b
$ ReadMode -> Int
forall a. Enum a => a -> Int
fromEnum ReadMode
m)

foreign import ccall safe "cdio/compat/read.h read_sector"
  readSector' :: C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> Lsn -> C.CInt -> IO C.CInt

-- | Read the data contained in the given number of sectors from the disc,
-- beginning with the specified sector.
readSectors :: Cdio -> Lsn -> ReadMode -> Word -> IO (Either DriverReturnCode BS.ByteString)
readSectors :: Cdio
-> Lsn
-> ReadMode
-> Word
-> IO (Either DriverReturnCode ByteString)
readSectors Cdio
c Lsn
o ReadMode
m Word
l = Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
readCdioSectors Cdio
c ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
 -> IO (Either DriverReturnCode ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' ->
    Ptr Cdio
-> Ptr (Ptr ()) -> Ptr CUInt -> Lsn -> CInt -> CUInt -> IO CInt
readSectors' Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' Lsn
o (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> CInt) -> Int -> CInt
forall a b. (a -> b) -> a -> b
$ ReadMode -> Int
forall a. Enum a => a -> Int
fromEnum ReadMode
m) (Word -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
l)

foreign import ccall safe "cdio/compat/read.h read_sectors"
  readSectors' :: C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> Lsn -> C.CInt -> C.CUInt -> IO C.CInt


-- | Similar to calling 'readSector' with 'AudioMode', depending on the driver
-- implementation.
readAudioSector :: Cdio -> Lsn -> IO (Either DriverReturnCode BS.ByteString)
readAudioSector :: Cdio -> Lsn -> IO (Either DriverReturnCode ByteString)
readAudioSector Cdio
c Lsn
o = Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
readCdioSectors Cdio
c ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
 -> IO (Either DriverReturnCode ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' ->
    Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> Lsn -> IO CInt
readAudioSector' Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' Lsn
o

foreign import ccall safe "cdio/compat/read.h read_audio_sector"
  readAudioSector' :: C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> Lsn -> IO C.CInt

-- | Similar to calling 'readSectors' with 'AudioMode', depending on the driver
-- implementation.
readAudioSectors :: Cdio -> Lsn -> Word -> IO (Either DriverReturnCode BS.ByteString)
readAudioSectors :: Cdio -> Lsn -> Word -> IO (Either DriverReturnCode ByteString)
readAudioSectors Cdio
c Lsn
o Word
l = Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
readCdioSectors Cdio
c ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
 -> IO (Either DriverReturnCode ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' ->
    Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> Lsn -> CUInt -> IO CInt
readAudioSectors' Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' Lsn
o (CUInt -> IO CInt) -> CUInt -> IO CInt
forall a b. (a -> b) -> a -> b
$ Word -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
l

foreign import ccall safe "cdio/compat/read.h read_audio_sectors"
  readAudioSectors' :: C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> Lsn -> C.CUInt -> IO C.CInt


-- | Read the raw data from a given number of sectors on the disc, beginning
-- with the specified sector.
readDataSectors
    :: Cdio
    -> Lsn
    -> Word
        -- ^ Sector size (e.g. 'Foreign.Libcdio.Sector.dataSize' or
        -- 'Foreign.Libcdio.Sector.dataSizeRawXa').
    -> Word
        -- ^ Number of sectors to read.
    -> IO (Either DriverReturnCode BS.ByteString)
readDataSectors :: Cdio
-> Lsn -> Word -> Word -> IO (Either DriverReturnCode ByteString)
readDataSectors Cdio
c Lsn
o Word
z Word
l = Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
readCdioSectors Cdio
c ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
 -> IO (Either DriverReturnCode ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' ->
    Ptr Cdio
-> Ptr (Ptr ()) -> Ptr CUInt -> Lsn -> CUShort -> CUInt -> IO CInt
readDataSectors' Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' Lsn
o (Word -> CUShort
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
z) (Word -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
l)

foreign import ccall safe "cdio/compat/read.h read_data_sectors"
  readDataSectors' :: C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> Lsn -> C.CUShort -> C.CUInt -> IO C.CInt


-- | Similar to calling 'readSector', depending on the driver implementation.
readDataModeSector
    :: Cdio
    -> Lsn
    -> Bool
        -- ^ If 'True' Form 2, otherwise Form 1 (see "Foreign.Libcdio.Sector").
    -> IO (Either DriverReturnCode BS.ByteString)
readDataModeSector :: Cdio -> Lsn -> Bool -> IO (Either DriverReturnCode ByteString)
readDataModeSector Cdio
c Lsn
o Bool
m = Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
readCdioSectors Cdio
c ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
 -> IO (Either DriverReturnCode ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' ->
    Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> Lsn -> CUChar -> IO CInt
readDataModeSector' Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' Lsn
o (CUChar -> IO CInt) -> CUChar -> IO CInt
forall a b. (a -> b) -> a -> b
$ Bool -> CUChar
forall a. Num a => Bool -> a
M.fromBool Bool
m

foreign import ccall safe "cdio/compat/read.h read_mode1_sector"
  readDataModeSector' :: C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> Lsn -> C.CUChar -> IO C.CInt

-- | Similar to calling 'readSectors', depending on the driver implementation.
readDataModeSectors
    :: Cdio
    -> Lsn
    -> Bool
        -- ^ If 'True' Form 2, otherwise Form 1 (see "Foreign.Libcdio.Sector").
    -> Word
    -> IO (Either DriverReturnCode BS.ByteString)
readDataModeSectors :: Cdio
-> Lsn -> Bool -> Word -> IO (Either DriverReturnCode ByteString)
readDataModeSectors Cdio
c Lsn
o Bool
m Word
l = Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
readCdioSectors Cdio
c ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
 -> IO (Either DriverReturnCode ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' ->
    Ptr Cdio
-> Ptr (Ptr ()) -> Ptr CUInt -> Lsn -> CUChar -> CUInt -> IO CInt
readDataModeSectors' Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' Lsn
o (Bool -> CUChar
forall a. Num a => Bool -> a
M.fromBool Bool
m) (Word -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
l)

foreign import ccall safe "cdio/compat/read.h read_mode1_sectors"
  readDataModeSectors' :: C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> Lsn -> C.CUChar -> C.CUInt -> IO C.CInt


-- | Similar to calling 'readSector', depending on the driver implementation.
readXaModeSector
    :: Cdio
    -> Lsn
    -> Bool
        -- ^ If 'True' Form 2, otherwise Form 1 (see "Foreign.Libcdio.Sector").
    -> IO (Either DriverReturnCode BS.ByteString)
readXaModeSector :: Cdio -> Lsn -> Bool -> IO (Either DriverReturnCode ByteString)
readXaModeSector Cdio
c Lsn
o Bool
m = Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
readCdioSectors Cdio
c ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
 -> IO (Either DriverReturnCode ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' ->
    Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> Lsn -> CUChar -> IO CInt
readXaModeSector' Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' Lsn
o (CUChar -> IO CInt) -> CUChar -> IO CInt
forall a b. (a -> b) -> a -> b
$ Bool -> CUChar
forall a. Num a => Bool -> a
M.fromBool Bool
m

foreign import ccall safe "cdio/compat/read.h read_mode2_sector"
  readXaModeSector' :: C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> Lsn -> C.CUChar -> IO C.CInt

-- | Similar to calling 'readSectors', depending on the driver implementation.
readXaModeSectors
    :: Cdio
    -> Lsn
    -> Bool
        -- ^ If 'True' Form 2, otherwise Form 1 (see "Foreign.Libcdio.Sector").
    -> Word
    -> IO (Either DriverReturnCode BS.ByteString)
readXaModeSectors :: Cdio
-> Lsn -> Bool -> Word -> IO (Either DriverReturnCode ByteString)
readXaModeSectors Cdio
c Lsn
o Bool
m Word
l = Cdio
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
readCdioSectors Cdio
c ((Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
 -> IO (Either DriverReturnCode ByteString))
-> (Ptr Cdio -> Ptr (Ptr ()) -> Ptr CUInt -> IO CInt)
-> IO (Either DriverReturnCode ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' ->
    Ptr Cdio
-> Ptr (Ptr ()) -> Ptr CUInt -> Lsn -> CUChar -> CUInt -> IO CInt
readXaModeSectors' Ptr Cdio
c' Ptr (Ptr ())
bs' Ptr CUInt
s' Lsn
o (Bool -> CUChar
forall a. Num a => Bool -> a
M.fromBool Bool
m) (Word -> CUInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
l)

foreign import ccall safe "cdio/compat/read.h read_mode2_sectors"
  readXaModeSectors' :: C.Ptr Cdio -> C.Ptr (C.Ptr ()) -> C.Ptr C.CUInt -> Lsn -> C.CUChar -> C.CUInt -> IO C.CInt