 foreign import ccall safe "gdal.h GDALGetMaskBand" c_getMaskBand
    :: (Band s t a) -> IO (Band s t Word8)
 
-getMaskBand :: Band s t a -> GDAL s (Band s t Word8)
-getMaskBand = liftIO . c_getMaskBand
+#c
+enum MaskFlag {
+     MaskAllValid = GMF_ALL_VALID,
+     MaskPerDataset = GMF_PER_DATASET,
+     MaskAlpha = GMF_ALPHA,
+     MaskNoData = GMF_NODATA
+};
+#endc
+
+{# enum MaskFlag  {} deriving (Eq, Bounded, Show) #}
+
+foreign import ccall unsafe "gdal.h GDALGetMaskFlags" c_getMaskFlags
+   :: (Band s t a) -> CInt
 
 
 instance GDALType Word8 where

           throwIfError "could not write block" $
              writeBlock_ b (fromIntegral x) (fromIntegral y)
                            (castPtr ptr)

foreign import ccall safe "gdal.h GDALWriteBlock" writeBlock_
   :: (RWBand s a) -> CInt -> CInt -> Ptr () -> IO CInt

  -> Int -> Int
  -> Int -> Int
  -> IO (Vector (Value a))
readBandIO band xoff yoff sx sy bx by =
  readMasked band $ \(b :: Band s t a') -> do
    fp <- mallocForeignPtrArray (bx * by)
    let dtype = fromEnumC (datatype (Proxy :: Proxy a'))
    withForeignPtr fp $ \ptr -> do
      throwIfError "could not advise read" $
        adviseRead_
          b
          (fromIntegral xoff)
          (fromIntegral yoff)
          (fromIntegral sx)
          (fromIntegral sy)
          (fromIntegral bx)
          (fromIntegral by)
          dtype
          (castPtr nullPtr)
      throwIfError "could not read band" $
        rasterIO_
          b
          (fromEnumC GF_Read) 
          (fromIntegral xoff)
          (fromIntegral yoff)
          (fromIntegral sx)
          (fromIntegral sy)
          (castPtr ptr)
          (fromIntegral bx)
          (fromIntegral by)
          dtype
          0
          0
    return $ St.unsafeFromForeignPtr0 fp (bx * by)
{-# INLINE readBandIO #-}

readMasked
  :: GDALType a
  => Band s t a
  -> (forall a'. GDALType a' => Band s t a' -> IO (Vector a'))
  -> IO (Vector (Value a))
readMasked band reader
  | hasFlag MaskPerDataset = useMaskBand
  | hasFlag MaskNoData     = useNoData
  | hasFlag MaskAllValid   = useAsIs
  | otherwise              = useMaskBand
  where
    hasFlag f = fromEnumC f .&. c_getMaskFlags band == fromEnumC f
    useAsIs = fmap (St.map Value) (reader band)
    useNoData = do
      mNodata <- c_bandNodataValue band
      let toValue = case mNodata of
                      Nothing -> Value
                      Just nd ->
                        \v -> if toNodata v == nd then NoData else Value v
      fmap (St.map toValue) (reader band)
    useMaskBand = do
      vs <- reader band
      mask <- c_getMaskBand band
      ms <- reader mask
      return $ St.zipWith (\v m -> if m/=0 then Value v else NoData) vs ms
{-# INLINE readMasked #-}

foreign import ccall safe "gdal.h GDALRasterAdviseRead" adviseRead_
    :: (Band s a t) -> CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> CInt
    -> Ptr (Ptr CChar) -> IO CInt


writeBand :: forall s a. GDALType a
  => (RWBand s a)
  -> Int -> Int
