{-# LANGUAGE CPP, RankNTypes #-}-- | Functions for interacting with bytes.moduleData.Conduit.Binary(-- * Files and @Handle@s-- | Note that most of these functions live in the @MonadResource@ monad-- to ensure resource finalization even in the presence of exceptions. In-- order to run such code, you will need to use @runResourceT@.-- ** SourcessourceFile,sourceHandle,sourceIOHandle,sourceFileRange-- ** Sinks,sinkFile,sinkHandle,sinkIOHandle-- ** Conduits,conduitFile-- * Utilities-- ** Sources,sourceLbs-- ** Sinks,head,dropWhile,take,drop-- ** Conduits,isolate,takeWhile,Data.Conduit.Binary.lines)whereimportPreludehiding(head,take,drop,takeWhile,dropWhile)importqualifiedData.ByteStringasSimportqualifiedData.ByteString.LazyasLimportData.Conduithiding(Source,Conduit,Sink,Pipe)importData.Conduit.List(sourceList)importControl.Exception(assert)importControl.Monad(unless)importControl.Monad.IO.Class(liftIO,MonadIO)importqualifiedSystem.IOasIOimportData.Word(Word8)importControl.Applicative((<$>))#if CABAL_OS_WINDOWSimportqualifiedSystem.Win32FileasF#elif NO_HANDLESimportqualifiedSystem.PosixFileasF#endif-- | Stream the contents of a file as binary data.---- Since 0.3.0sourceFile::MonadResourcem=>FilePath->GSourcemS.ByteStringsourceFilefp=#if CABAL_OS_WINDOWS || NO_HANDLESbracketP(F.openReadfp)F.closeloopwherelooph=liftIO(F.readh)>>=maybe(return())(\bs->yieldbs>>looph)#elsesourceIOHandle(IO.openBinaryFilefpIO.ReadMode)#endif-- | Stream the contents of a 'IO.Handle' as binary data. Note that this-- function will /not/ automatically close the @Handle@ when processing-- completes, since it did not acquire the @Handle@ in the first place.---- Since 0.3.0sourceHandle::MonadIOm=>IO.Handle->GSourcemS.ByteStringsourceHandleh=loopwhereloop=dobs<-liftIO(S.hGetSomeh4096)ifS.nullbsthenreturn()elseyieldbs>>loop-- | An alternative to 'sourceHandle'.-- Instead of taking a pre-opened 'IO.Handle', it takes an action that opens-- a 'IO.Handle' (in read mode), so that it can open it only when needed-- and closed it as soon as possible.---- Since 0.3.0sourceIOHandle::MonadResourcem=>IOIO.Handle->GSourcemS.ByteStringsourceIOHandlealloc=bracketPallocIO.hClosesourceHandle-- | Stream all incoming data to the given 'IO.Handle'. Note that this function-- will /not/ automatically close the @Handle@ when processing completes.---- Since 0.3.0sinkHandle::MonadIOm=>IO.Handle->GInfSinkS.ByteStringmsinkHandleh=awaitForever$liftIO.S.hPuth-- | An alternative to 'sinkHandle'.-- Instead of taking a pre-opened 'IO.Handle', it takes an action that opens-- a 'IO.Handle' (in write mode), so that it can open it only when needed-- and close it as soon as possible.---- Since 0.3.0sinkIOHandle::MonadResourcem=>IOIO.Handle->GInfSinkS.ByteStringmsinkIOHandlealloc=bracketPallocIO.hClosesinkHandle-- | Stream the contents of a file as binary data, starting from a certain-- offset and only consuming up to a certain number of bytes.---- Since 0.3.0sourceFileRange::MonadResourcem=>FilePath->MaybeInteger-- ^ Offset->MaybeInteger-- ^ Maximum count->GSourcemS.ByteStringsourceFileRangefpoffsetcount=bracketP(IO.openBinaryFilefpIO.ReadMode)IO.hClosestartwherestarthandle=docaseoffsetofNothing->return()Justoff->liftIO$IO.hSeekhandleIO.AbsoluteSeekoffcasecountofNothing->pullUnlimitedhandleJustc->pullLimited(fromIntegerc)handlepullUnlimitedhandle=dobs<-liftIO$S.hGetSomehandle4096ifS.nullbsthenreturn()elsedoyieldbspullUnlimitedhandlepullLimitedchandle=dobs<-liftIO$S.hGetSomehandle(minc4096)letc'=c-S.lengthbsassert(c'>=0)$ifS.nullbsthenreturn()elsedoyieldbspullLimitedc'handle-- | Stream all incoming data to the given file.---- Since 0.3.0sinkFile::MonadResourcem=>FilePath->GInfSinkS.ByteStringmsinkFilefp=sinkIOHandle(IO.openBinaryFilefpIO.WriteMode)-- | Stream the contents of the input to a file, and also send it along the-- pipeline. Similar in concept to the Unix command @tee@.---- Since 0.3.0conduitFile::MonadResourcem=>FilePath->GInfConduitS.ByteStringmS.ByteStringconduitFilefp=bracketP(IO.openBinaryFilefpIO.WriteMode)IO.hClosegowheregoh=awaitForever$\bs->liftIO(S.hPuthbs)>>yieldbs-- | Ensure that only up to the given number of bytes are consume by the inner-- sink. Note that this does /not/ ensure that all of those bytes are in fact-- consumed.---- Since 0.3.0isolate::Monadm=>Int->GLConduitS.ByteStringmS.ByteStringisolate=loopwhereloop0=return()loopcount=dombs<-awaitcasembsofNothing->return()Justbs->dolet(a,b)=S.splitAtcountbscasecount-S.lengthaof0->dounless(S.nullb)$leftoverbyieldacount'->assert(S.nullb)$yielda>>loopcount'-- | Return the next byte from the stream, if available.---- Since 0.3.0head::Monadm=>GLSinkS.ByteStringm(MaybeWord8)head=dombs<-awaitcasembsofNothing->returnNothingJustbs->caseS.unconsbsofNothing->headJust(w,bs')->leftoverbs'>>return(Justw)-- | Return all bytes while the predicate returns @True@.---- Since 0.3.0takeWhile::Monadm=>(Word8->Bool)->GLConduitS.ByteStringmS.ByteStringtakeWhilep=loopwhereloop=await>>=maybe(return())gogobs|S.nullx=next|otherwise=yieldx>>nextwherenext=ifS.nullythenloopelseleftovery(x,y)=S.spanpbs-- | Ignore all bytes while the predicate returns @True@.---- Since 0.3.0dropWhile::Monadm=>(Word8->Bool)->GLSinkS.ByteStringm()dropWhilep=loopwhereloop=dombs<-awaitcaseS.dropWhilep<$>mbsofNothing->return()Justbs|S.nullbs->loop|otherwise->leftoverbs-- | Take the given number of bytes, if available.---- Since 0.3.0take::Monadm=>Int->GLSinkS.ByteStringmL.ByteStringtaken0=gon0idwheregonfront=await>>=maybe(return$L.fromChunks$front[])go'wherego'bs=caseS.lengthbs`compare`nofLT->go(n-S.lengthbs)(front.(bs:))EQ->return$L.fromChunks$front[bs]GT->let(x,y)=S.splitAtnbsinassert(not$S.nully)$leftovery>>return(L.fromChunks$front[x])-- | Drop up to the given number of bytes.---- Since 0.5.0drop::Monadm=>Int->GLSinkS.ByteStringm()drop=gowheregon=await>>=maybe(return())go'wherego'bs=caseS.lengthbs`compare`nofLT->go(n-S.lengthbs)EQ->return()GT->lety=S.dropnbsinassert(not$S.nully)$leftovery>>return()-- | Split the input bytes into lines. In other words, split on the LF byte-- (10), and strip it from the output.---- Since 0.3.0lines::Monadm=>GInfConduitS.ByteStringmS.ByteStringlines=loopidwhereloopfront=awaitE>>=either(finishfront)(gofront)finishfrontr=letfinal=frontS.emptyinunless(S.nullfinal)(yieldfinal)>>returnrgosofarmore=caseS.unconssecondofJust(_,second')->yield(sofarfirst)>>goidsecond'Nothing->letrest=sofarmoreinloop$S.appendrestwhere(first,second)=S.breakByte10more-- | Stream the chunks from a lazy bytestring.---- Since 0.5.0sourceLbs::Monadm=>L.ByteString->GSourcemS.ByteStringsourceLbs=sourceList.L.toChunks