1 {-# LANGUAGE RecordWildCards, BangPatterns #-}
2 -- | This module declares (low-level) data types for Java .class files
3 -- structures, and Binary instances to read/write them.
11 FieldSignature, MethodSignature (..), ReturnSignature (..)
16 import Control.Applicative
18 import Data.Binary.IEEE754
19 import Data.Binary.Get
20 import Data.Binary.Put
23 import qualified Data.ByteString.Lazy as B
25 -- | Read one-byte Char
29 return $ chr (fromIntegral x)
31 -- | Generic .class file format
32 data ClassFile = ClassFile {
33 magic :: Word32, -- ^ Magic value: 0xCAFEBABE
34 minorVersion :: Word16,
35 majorVersion :: Word16,
36 constsPoolSize :: Word16, -- ^ Number of items in constants pool
37 constsPool :: [CpInfo], -- ^ Constants pool itself
38 accessFlags :: Word16, -- ^ See @JVM.Types.AccessFlag@
39 thisClass :: Word16, -- ^ Constants pool item index for this class
40 superClass :: Word16, -- ^ --/-- for super class, zero for java.lang.Object
41 interfacesCount :: Word16, -- ^ Number of implemented interfaces
42 interfaces :: [Word16], -- ^ Constants pool item indexes for implemented interfaces
43 classFieldsCount :: Word16, -- ^ Number of class fileds
44 classFields :: [FieldInfo], -- ^ Class fields
45 classMethodsCount :: Word16, -- ^ Number of class methods
46 classMethods :: [MethodInfo], -- ^ Class methods
47 classAttributesCount :: Word16, -- ^ Number of class attributes
48 classAttributes :: [AttributeInfo] -- ^ Class attributes
52 instance Binary ClassFile where
53 put (ClassFile {..}) = do
67 forM_ classMethods put
68 put classAttributesCount
69 forM_ classAttributes put
76 pool <- replicateM (fromIntegral poolsize - 1) get
80 interfacesCount <- get
81 ifaces <- replicateM (fromIntegral interfacesCount) get
82 classFieldsCount <- get
83 classFields <- replicateM (fromIntegral classFieldsCount) get
84 classMethodsCount <- get
85 classMethods <- replicateM (fromIntegral classMethodsCount) get
87 as <- replicateM (fromIntegral $ asCount - 1) get
88 return $ ClassFile magic minor major poolsize pool af this super
89 interfacesCount ifaces classFieldsCount classFields classMethodsCount classMethods asCount as
91 -- | Field signature format
101 | ObjectType String -- ^ L <class name>
102 | Array (Maybe Int) FieldType -- ^ [<type>
105 instance Show FieldType where
106 show SignedByte = "byte"
107 show CharByte = "char"
108 show DoubleType = "double"
109 show FloatType = "float"
111 show LongInt = "long"
112 show ShortInt = "short"
113 show BoolType = "bool"
114 show (ObjectType s) = "Object " ++ s
115 show (Array Nothing t) = show t ++ "[]"
116 show (Array (Just n) t) = show t ++ "[" ++ show n ++ "]"
118 -- | Class field signature
119 type FieldSignature = FieldType
121 -- | Try to read integer value from decimal representation
122 getInt :: Get (Maybe Int)
127 else return $ Just (read s)
129 getDigits :: Get [Char]
131 c <- lookAhead getChar8
139 instance Binary FieldType where
140 put SignedByte = put 'B'
141 put CharByte = put 'C'
142 put DoubleType = put 'D'
143 put FloatType = put 'F'
144 put IntType = put 'I'
145 put LongInt = put 'J'
146 put ShortInt = put 'S'
147 put BoolType = put 'Z'
148 put (ObjectType name) = put 'L' >> put name
149 put (Array Nothing sig) = put '[' >> put sig
150 put (Array (Just n) sig) = put '[' >> put (show n) >> put sig
155 'B' -> return SignedByte
156 'C' -> return CharByte
157 'D' -> return DoubleType
158 'F' -> return FloatType
159 'I' -> return IntType
160 'J' -> return LongInt
161 'S' -> return ShortInt
162 'Z' -> return BoolType
164 name <- getToSemicolon
165 return (ObjectType name)
169 return (Array mbSize sig)
170 _ -> fail $ "Unknown signature opening symbol: " ++ [b]
172 -- | Read string up to `;'
173 getToSemicolon :: Get String
179 next <- getToSemicolon
182 -- | Return value signature
183 data ReturnSignature =
188 instance Show ReturnSignature where
189 show (Returns t) = show t
190 show ReturnsVoid = "Void"
192 instance Binary ReturnSignature where
193 put (Returns sig) = put sig
194 put ReturnsVoid = put 'V'
197 x <- lookAhead getChar8
199 'V' -> skip 1 >> return ReturnsVoid
202 -- | Method argument signature
203 type ArgumentSignature = FieldType
205 -- | Class method argument signature
206 data MethodSignature =
207 MethodSignature [ArgumentSignature] ReturnSignature
210 instance Show MethodSignature where
211 show (MethodSignature args ret) = "(" ++ intercalate ", " (map show args) ++ ") returns " ++ show ret
213 instance Binary MethodSignature where
214 put (MethodSignature args ret) = do
223 fail "Cannot parse method signature: no starting `(' !"
227 fail "Internal error: method signature without `)' !?"
229 return (MethodSignature args ret)
231 -- | Read arguments signatures (up to `)')
232 getArgs :: Get [ArgumentSignature]
233 getArgs = whileJust getArg
235 getArg :: Get (Maybe ArgumentSignature)
237 x <- lookAhead getChar8
242 whileJust :: (Monad m) => m (Maybe a) -> m [a]
251 -- | Constant pool item format
253 CONSTANT_Class {nameIndex :: Word16} -- ^ 7
254 | CONSTANT_Fieldref {classIndex :: Word16, nameAndTypeIndex :: Word16} -- ^ 9
255 | CONSTANT_Methodref {classIndex :: Word16, nameAndTypeIndex :: Word16} -- ^ 10
256 | CONSTANT_InterfaceMethodref {classIndex :: Word16, nameAndTypeIndex :: Word16}-- ^ 11
257 | CONSTANT_String {stringIndex :: Word16} -- ^ 8
258 | CONSTANT_Integer {fourBytes :: Word32} -- ^ 3
259 | CONSTANT_Float Float -- ^ 4
260 | CONSTANT_Long Word64 -- ^ 5
261 | CONSTANT_Double Double -- ^ 6
262 | CONSTANT_NameAndType {nameIndex :: Word16, signatureIndex :: Word16} -- ^ 12
263 | CONSTANT_Utf8 {stringLength :: Word16, stringBytes :: B.ByteString} -- ^ 1
264 | CONSTANT_Unicode {stringLength :: Word16, stringBytes :: B.ByteString} -- ^ 2
267 instance Binary CpInfo where
268 put (CONSTANT_Class i) = putWord8 7 >> put i
269 put (CONSTANT_Fieldref i j) = putWord8 9 >> put i >> put j
270 put (CONSTANT_Methodref i j) = putWord8 10 >> put i >> put j
271 put (CONSTANT_InterfaceMethodref i j) = putWord8 11 >> put i >> put j
272 put (CONSTANT_String i) = putWord8 8 >> put i
273 put (CONSTANT_Integer x) = putWord8 3 >> put x
274 put (CONSTANT_Float x) = putWord8 4 >> putFloat32be x
275 put (CONSTANT_Long x) = putWord8 5 >> put x
276 put (CONSTANT_Double x) = putWord8 6 >> putFloat64be x
277 put (CONSTANT_NameAndType i j) = putWord8 12 >> put i >> put j
278 put (CONSTANT_Utf8 l bs) = putWord8 1 >> put l >> putLazyByteString bs
279 put (CONSTANT_Unicode l bs) = putWord8 2 >> put l >> putLazyByteString bs
287 bs <- getLazyByteString (fromIntegral l)
288 return $ CONSTANT_Utf8 l bs
291 bs <- getLazyByteString (fromIntegral l)
292 return $ CONSTANT_Unicode l bs
293 3 -> CONSTANT_Integer <$> get
294 4 -> CONSTANT_Float <$> getFloat32be
295 5 -> CONSTANT_Long <$> get
296 6 -> CONSTANT_Double <$> getFloat64be
297 7 -> CONSTANT_Class <$> get
298 8 -> CONSTANT_String <$> get
299 9 -> CONSTANT_Fieldref <$> get <*> get
300 10 -> CONSTANT_Methodref <$> get <*> get
301 11 -> CONSTANT_InterfaceMethodref <$> get <*> get
302 12 -> CONSTANT_NameAndType <$> get <*> get
303 _ -> fail $ "Unknown constants pool entry tag: " ++ show tag
305 -- | Class field format
306 data FieldInfo = FieldInfo {
307 fieldAccessFlags :: Word16,
308 fieldNameIndex :: Word16,
309 fieldSignatureIndex :: Word16,
310 fieldAttributesCount :: Word16,
311 fieldAttributes :: [AttributeInfo] }
314 instance Binary FieldInfo where
315 put (FieldInfo {..}) = do
318 put fieldSignatureIndex
319 put fieldAttributesCount
320 forM_ fieldAttributes put
327 as <- replicateM (fromIntegral n) get
328 return $ FieldInfo af ni si n as
330 -- | Class method format
331 data MethodInfo = MethodInfo {
332 methodAccessFlags :: Word16,
333 methodNameIndex :: Word16,
334 methodSignatureIndex :: Word16,
335 methodAttributesCount :: Word16,
336 methodAttributes :: [AttributeInfo] }
339 instance Binary MethodInfo where
340 put (MethodInfo {..}) = do
341 put methodAccessFlags
343 put methodSignatureIndex
344 put methodAttributesCount
345 forM_ methodAttributes put
353 as <- replicateM (fromIntegral n) get
354 return $ MethodInfo af ni si n as
356 -- | Any (class/ field/ method/ ...) attribute format.
357 -- Some formats specify special formats for @attributeValue@.
358 data AttributeInfo = AttributeInfo {
359 attributeName :: Word16,
360 attributeLength :: Word32,
361 attributeValue :: B.ByteString }
364 instance Binary AttributeInfo where
365 put (AttributeInfo {..}) = do
367 putWord32be attributeLength
368 putLazyByteString attributeValue
374 value <- getLazyByteString (fromIntegral len)
375 return $ AttributeInfo name len value