Sto provando ad analizzare i dati binari usando pipe-attoparsec in Haskell. Il motivo per cui i pipe (proxy) sono coinvolti consiste nell'interlacciare la lettura con l'analisi per evitare l'utilizzo di memoria elevata per file di grandi dimensioni. Molti formati binari sono basati su blocchi (o blocchi) e le loro dimensioni sono spesso descritte da un campo nel file. Non sono sicuro di ciò che viene chiamato un parser per tale blocco, ma questo è ciò che intendo per "sub-parser" nel titolo. Il problema che ho è di implementarli in modo conciso senza un ingombro di memoria potenzialmente grande. Ho inventato due alternative che falliscono in qualche modo."Sub-parser" in pipe-attoparsec
L'alternativa 1 è leggere il blocco in un test separato e avviare un parser separato per esso. Mentre conciso, un grande blocco causerà un uso di memoria elevato.
L'alternativa 2 è di mantenere l'analisi nello stesso contesto e tenere traccia del numero di byte consumati. Questo tracciamento è soggetto a errori e sembra infestare tutti i parser che compongono nell'ultimo blockParser. Per un file di input non valido potrebbe anche sprecare tempo analizzando ulteriormente di quanto indicato dal campo delle dimensioni prima che la dimensione tracciata possa essere confrontata.
import Control.Proxy.Attoparsec
import Control.Proxy.Trans.Either
import Data.Attoparsec as P
import Data.Attoparsec.Binary
import qualified Data.ByteString as BS
parser = do
size <- fromIntegral <$> anyWord32le
-- alternative 1 (ignore the Either for simplicity):
Right result <- parseOnly blockParser <$> P.take size
return result
-- alternative 2
(result, trackedSize) <- blockparser
when (size /= trackedSize) $ fail "size mismatch"
return result
blockParser = undefined
main = withBinaryFile "bin" ReadMode go where
go h = fmap print . runProxy . runEitherK $ session h
session h = printD <-< parserD parser <-< throwParsingErrors <-< parserInputD <-< readChunk h 128
readChunk h n() = runIdentityP go where
go = do
c <- lift $ BS.hGet h n
unless (BS.null c) $ respond c *> go
Inserire una pipe che conti i suoni upstream interessanti, ma come farà a sapere quanti byte contare? Questo valore viene rilevato solo dal parser downstream, che non può chiamare direttamente la richiesta con il valore come parametro, poiché viene eseguito da parserD. – absence
@absence Bene, per ora ignora l'interfaccia pipe-attoparsec perché Renzo e io lo sistemeremo presto. Il parser di input fisso utilizza internamente una pipe che limita il conteggio dei byte. Pensa a questo: 'parser1 >> (restrict n> -> parser2) >> parser3'. La larghezza fissa combinatoria inserisce qualcosa come "restrict" a monte di quel dato parser. È più complicato di così, ma abbastanza simile nello spirito. –
I collegamenti sono morti – SwiftsNamesake