5

シンプルな attoparsec ベースのpdf パーサーがあります。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 で?私のコードでは?回避策はありますか?私にとって本当に喫緊の課題です。

ありがとう。

4

1 に答える 1

2

編集2:Pdf / Parser/Valueに新しいパーサーを作成しました

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)

次に、このパーサーをで使用しましたparseValue。これはすべての場合に機能します。なぜchoice適切にバックトラックできないのか、おそらくアトパーセクのバグなのかわかりません。

parseValue編集:私があなたのトップレベルをに置き換えると、それが機能することに気づきましたparseDictparseStreamの選択肢から削除しても機能しparseValueます。attoparsecは、最上位の辞書の完成後に「parseStream」にコミットしたと思います。したがって、このエラーにつながるより多くの入力(スペース、「ストリーム」トークンなど)を期待しています。この時点で、解決する必要があるこれら2つの解析オプションの間にあいまいさがあります。入力全体が利用できるのに、なぜ正しく機能するのかわかりません。パーサーにチャンクが供給されたときのように、エラーが報告されると思います。

今のところ、私はあなたのコード、またはおそらくアトパーセクのいずれかにバグがあると思います。バイト文字列チャンクを手動で読み取り、それをアトパーセクパーサーにフィードすることで、次のテストを実行しました。

*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でもありません。

于 2012-01-25T00:21:15.427 に答える