Javaクラスファイル解析(途中まで)

30分プログラム、その109。Javaのクラスファイル解析、もしくはParsecによるバイナリファイルの解析。

最近、Java仮想マシン仕様 (The Java series)を読んでいるので、勉強のために。全部はやりきれなかったので、先頭のフィールドのみ。

こういうのはC言語のほうがいいんじゃないかな?と思いつつもHaskellで。

使い方

$ javad ../../junk/ConvTest.class
magic: 0xcafebabe
minorVersion: 0
majorVersion: 49

ソースコード

import Control.Monad
import System.Environment
import Data.Word
import Data.Bits

import Text.ParserCombinators.Parsec
import Text.Printf
data ClassFile = ClassFile { 
      magic::Int ,
      minorVersion::Int,
      majorVersion::Int}

instance Show ClassFile where
    show c = printf 
             (unlines ["magic: 0x%x",
                      "minorVersion: %d",
                      "majorVersion: %d"]) 
             (magic c) 
             (minorVersion c) 
             (majorVersion c)

x << n = shift x n

type BParser a = GenParser Word8 () a

bsatisfy :: (Word8 -> Bool) -> BParser Word8
bsatisfy f = tokenPrim 
             (\s -> show s) 
             (\pos _ _ -> incSourceLine pos 1) 
             (\s -> if f s then Just s else Nothing)

u1 :: BParser Int
u1 = bsatisfy (const True) >>= return.fromIntegral
             
uN :: Int->BParser Int
uN n = do xs <- replicateM n u1
          return $ foldl1 (\x y -> (x<<8) + y) xs

u2 :: BParser Int
u2 = uN 2

u4 :: BParser Int
u4 = uN 4

pMagic :: BParser Int
pMagic = u4
pMinor = u2
pMajor = u2

pClass :: BParser ClassFile
pClass =  do m <- pMagic
             minor <- pMinor
             major <- pMajor
             return $ ClassFile m minor major

run p input = case (parse p "" input) of
                Left err -> do putStr "parse error at "
                               print err
                Right x -> print x

--f = run pClass [0xCa,0xfe,0xba,0xbe,0x00,0x01,0x00,0x2]

main = do (x:xs) <- getArgs
          content <- readFile x
          run pClass $ map (fromIntegral.fromEnum) content