2012-01-24 17 views
5

私は単純なattoparsecベースのpdf parserを持っています。それはiterateeで使用するまでうまく動作します。 入力のサイズがバッファサイズを超える場合。入力がバッファサイズより大きい場合、attoparsec-iterateeは機能しません

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!!! 

入力:だから

<< /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 >> 

は、パーサがiterateeせずに動作しますが、十分に大きな塊で動作しますが、小さな塊では動作しません。 iterateeのバグ? attoparsec-iterateeでは?私のコードでは?回避策はありますか?それは私にとって本当に緊急の問題です。

ありがとうございました。

+0

バグの場所はわかりませんが、十分に大きなチャンクサイズを使用するだけですか?あるいは 'Iteratees'の代わりに' ByteString'sを使うのですか? –

+0

pdf値は任意の長さにすることができるので、十分なチャンクサイズはありません。 Re ByteString:あなたはレイジーIOですか? Pdfはランダムアクセスが必要であり、参照テーブルは通常ファイルの最後にあります。ですから、この特定のケースではIO - = "strict"となり、メモリを非効率的に使用します。 – Yuras

+0

'Iteratee'はランダムアクセスを許可していますか?私はそれを聞いていない(何かを意味するものではない、私はユーザーではない)。ランダムアクセスが必要な場合は、ファイル全体を一度に読み取るか、ファイルの一部を検索して読み取るための足場が必要です。可能であれば、最初のオプションは** much ** simplerです。 –

答えて

2

編集2:私は、その後、parseValueでこのパーサを使用

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) 

PDF /パーサ/バリューに新しいパーサを作成しました。これはすべての場合に有効です。私はchoiceが正しくbacktrackに失敗した理由、たぶんattoparsecバグを知らないのですか?

編集:トップレベルのparseValueparseDictに置き換えると、それが機能します。 をparseValueの選択肢から削除しても機能します。私はattoparsecがトップレベルの辞書の完成後に "parseStream"にコミットしたと思うので、このエラーに至るより多くの入力(スペース、 "ストリーム"トークンなど)が予想されます。この時点で、解決する必要があるこれらの2つの解析オプションにはあいまいさがあります。私は、入力全体が利用可能なときになぜそれが適切に動作するのかわかりません。あなたのパーサにチャンクが与えられたときにエラーが報告されると思います。

今のところ、あなたのコードかattoparsecのどちらかにバグがあると思われます。私は手動でバイト文字列のチャンクを読んで、あなたのattoparsecパーサーにそれを供給することによって、次のテストを実行しました:何らかの理由で

*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" 

、あなたのパーサは、チャンクでデータを受信したいとしていないようだ、と(第3の受信時に、空の失敗します)チャンクを生成する。あなたのパーサーがどこに間違っているのかはまだ分かっていませんが、iterateeやattoparsec-iterateeは間違いありません。

+0

あなたはそうです、iterateeとattoparsec-iterateeの両方がそれとは関係ないようです。 ty、John – Yuras

+0

曖昧な理由を説明してください。 'parserDict'は' stream 'が見つからないと失敗し、 'choice'は次のオプション' parseDict'を試みます。 – Yuras

+0

申し訳ありませんが、 "ストリーム"が見つからないと、 'parseStream'が失敗します。 – Yuras

関連する問題