2012-01-24 11 views
5

Mam prosty interfejs oparty na attoparsec pdf parser. Działa dobrze, dopóki nie zostanie użyty z iteratee. Gdy rozmiar wejścia przekracza rozmiar bufora.Funkcja attoparsec-iteratee nie działa, gdy wejście jest większe niż rozmiar bufora

import qualified Data.ByteString as BS 
import qualified Data.Iteratee as I 
import qualified Data.Attoparsec as P 
import qualified Data.Attoparsec.Iteratee as P 
import System.Environment (getArgs) 
import Control.Monad 

import Pdf.Parser.Value 

main :: IO() 
main = do 
    [i] <- getArgs 
    liftM (P.parseOnly parseValue) (BS.readFile i) >>= print -- works 
    I.fileDriverRandomVBuf 2048 (P.parserToIteratee parseValue) i >>= print -- works 
    I.fileDriverRandomVBuf 1024 (P.parserToIteratee parseValue) i >>= print -- DOES NOT works!!! 

Wejście:

<< /Annots [ 404 0 R 547 0 R ] /ArtBox [ 0.000000 0.000000 612.000000 792.000000 ] /BleedBox [ 0.000000 0.000000 612.000000 792.000000 ] /Contents [ 435 0 R 436 0 R 437 0 R 444 0 R 448 0 R 449 0 R 450 0 R 453 0 R ] /CropBox [ 0.000000 0.000000 612.000000 792.000000 ] /Group 544 0 R /MediaBox [ 0.000000 0.000000 612.000000 792.000000 ] /Parent 239 0 R /Resources << /ColorSpace << /CS0 427 0 R /CS1 427 0 R /CS2 428 0 R >> /ExtGState << /GS0 430 0 R /GS1 431 0 R /GS2 469 0 R /GS3 475 0 R /GS4 439 0 R /GS5 480 0 R /GS6 485 0 R /GS7 491 0 R /GS8 497 0 R >> /Font << /C2_0 447 0 R /T1_0 421 0 R /T1_1 422 0 R /T1_2 423 0 R /T1_3 424 0 R /T1_4 425 0 R /T1_5 426 0 R /T1_6 438 0 R >> /ProcSet [ /PDF /Text /ImageC /ImageI ] /Properties << /MC0 << /Metadata 502 0 R >> >> /XObject << /Fm0 451 0 R /Fm1 504 0 R /Fm2 513 0 R /Fm3 515 0 R /Fm4 517 0 R /Fm5 526 0 R /Fm6 528 0 R /Fm7 537 0 R /Fm8 539 0 R /Im0 540 0 R /Im1 541 0 R /Im2 452 0 R /Im3 542 0 R /Im4 543 0 R >> >> /Rotate 0 /StructParents 1 /TrimBox [ 0.000000 0.000000 612.000000 792.000000 ] /Type /Page >> 

więc, parser działa bez iteratee, współpracuje z kawałkami wystarczająco duży, ale nie działa z mniejszych kawałków. Błąd w iteratee? W attoparsec-iteratee? W moim kodzie? Czy istnieje jakieś obejście? To dla mnie bardzo pilna kwestia.

Dzięki.

+0

Nie mam pojęcia, gdzie jest błąd, ale czy można po prostu użyć wystarczająco dużego rozmiaru porcji? Lub użyć 'ByteString's zamiast' Iteratees'? –

+0

Wartość pdf może być dowolnie długa, więc nie ma wystarczająco dużego rozmiaru porcji. Re ByteString: masz na myśli leniwego IO? Pdf wymaga dostępu losowego, a tabela odniesienia zwykle znajduje się na końcu pliku. Tak leniwy IO ~ = "ścisły" w tym konkretnym przypadku i użyje pamięci nieefektywnie. – Yuras

+0

Czy 'Iteratee's umożliwiają dostęp losowy? Nie słyszałem o tym (nic nie znaczę, nie jestem użytkownikiem). Jeśli potrzebujesz dostępu losowego, przeczytaj cały plik naraz lub skorzystaj z rusztowania, aby wyszukać i odczytać fragmenty pliku. Jeśli to możliwe, pierwsza opcja jest ** znacznie ** prostsza. –

Odpowiedz

2

Edit 2: I stworzył nowy parser w PDF/parser/wartość

dictOrStream :: Parser PdfValue 
dictOrStream = do 
    dict <- parseDict 
    P.skipSpace 
    let s1 = do 
      P.string $ fromString "stream" 
      content <- P.manyTill P.anyWord8 $ P.endOfLine >> P.string (fromString "endstream") 
      return $ PdfValStream (PdfStream dict (BS.pack content)) 
    s1 <|> return (PdfValDict dict) 

następnie skorzystał z tego parsera w parseValue. Działa to we wszystkich twoich przypadkach. Nie wiem, dlaczego choice nie można poprawnie przesłuchać, być może bug attoparsec?

Edycja: zauważam, że jeśli zmienię Twój najwyższy poziom parseValue na parseDict, to działa. Działa to również, gdy usuwam parseStream z opcji dostępnych w parseValue. Myślę, że attoparsec zobowiązał się do "parseStream" po zakończeniu słownika najwyższego poziomu, dlatego spodziewa się więcej danych wejściowych (spacja, token "stream" itp.) Prowadzących do tego błędu. W tym momencie istnieje niejednoznaczność między tymi dwiema opcjami analizowania, które należy rozwiązać. Nie wiem, dlaczego działa poprawnie, gdy całe wejście jest dostępne; Spodziewam się, że zgłaszany jest błąd, gdy parser jest karmiony kawałkami.

Od tej pory podejrzewam błąd w kodzie lub ewentualnie attoparsec. Pobiegłem następujący test ręcznie czytanie fragmentów bytestring i karmienie go do attoparsec parsera:

*Main System.IO> h <- openFile "test.pdf" ReadMode 
*Main System.IO Data.ByteString> let hget = hGetSome h 1024 
*Main System.IO Data.ByteString> b <- hget 
*Main System.IO Data.ByteString> let r = P.parse parseValue b 
*Main System.IO Data.ByteString> r 
Partial _ 
*Main System.IO Data.ByteString> b <- hget 
*Main System.IO Data.ByteString> let r' = P.feed r b 
*Main System.IO Data.ByteString> r' 
Partial _ 
*Main System.IO Data.ByteString> b <- hget 
*Main System.IO Data.ByteString> Data.ByteString.length b 
0 
*Main System.IO Data.ByteString> let r'2 = P.feed r' b 
*Main System.IO Data.ByteString> r'2 
Fail "<< /Annots [ 404 0 R 547 0 R ] /ArtBox [ 0.000000 0.000000 612.000000 792.000000 ] /BleedBox [ 0.000000 0.000000 612.000000 792.000000 ] /Contents [ 435 0 R 436 0 R 437 0 R 444 0 R 448 0 R 449 0 R 450 0 R 453 0 R ] /CropBox [ 0.000000 0.000000 612.000000 792.000000 ] /Group 544 0 R /MediaBox [ 0.000000 0.000000 612.000000 792.000000 ] /Parent 239 0 R /Resources << /ColorSpace << /CS0 427 0 R /CS1 427 0 R /CS2 428 0 R >> /ExtGState << /GS0 430 0 R /GS1 431 0 R /GS2 469 0 R /GS3 475 0 R /GS4 439 0 R /GS5 480 0 R /GS6 485 0 R /GS7 491 0 R /GS8 497 0 R >> /Font << /C2_0 447 0 R /T1_0 421 0 R /T1_1 422 0 R /T1_2 423 0 R /T1_3 424 0 R /T1_4 425 0 R /T1_5 426 0 R /T1_6 438 0 R >> /ProcSet [ /PDF /Text /ImageC /ImageI ] /Properties << /MC0 << /Metadata 502 0 R >> >> /XObject << /Fm0 451 0 R /Fm1 504 0 R /Fm2 513 0 R /Fm3 515 0 R /Fm4 517 0 R /Fm5 526 0 R /Fm6 528 0 R /Fm7 537 0 R /Fm8 539 0 R /Im0 540 0 R /Im1 541 0 R /Im2 452 0 R /Im3 542 0 R /Im4 543 0 R >> >> /Rotate 0 /StructParents 1 /TrimBox [ 0.000000 0.000000" [] "Failed reading: empty" 

z jakiegoś powodu Twój parser nie lubią odbierać dane w kawałki, a nie po otrzymaniu trzeciej (pusty) porcja bez pobierania żadnych danych wejściowych. Jeszcze nie zorientowałem się, gdzie twój parser idzie źle, ale zdecydowanie nie jest iteratee lub attoparsec-iteratee.

+0

Masz rację, wygląda na to, że zarówno iteratee, jak i attoparsec-iteratee nie mają z tym nic wspólnego. ty, John – Yuras

+0

Proszę wyjaśnić, dlaczego jest niejednoznaczny? Spodziewam się, że 'parserDict' się nie powiedzie, jeśli nie znajdziesz" stream ", a' choice' spróbuje następnej opcji - 'parseDict'. – Yuras

+0

Przepraszam, mam na myśli, że 'parseStream' nie powiedzie się, jeśli nie znajdzie" strumienia " – Yuras