diff --git a/java-classfile.cabal b/java-classfile.cabal index 6efd041..09294fe 100644 --- a/java-classfile.cabal +++ b/java-classfile.cabal @@ -28,6 +28,7 @@ library Language.Java.Classfile Language.Java.Classfile.Extract Language.Java.Classfile.Extractable + Language.Java.Classfile.FromBigEndian Language.Java.Classfile.Version other-modules: Paths_java_classfile diff --git a/src/Language/Java/Classfile/Extract.hs b/src/Language/Java/Classfile/Extract.hs index 88ee4d5..c8fa394 100644 --- a/src/Language/Java/Classfile/Extract.hs +++ b/src/Language/Java/Classfile/Extract.hs @@ -1,8 +1,9 @@ {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE InstanceSigs #-} -module Language.Java.Classfile.Extract (Extract()) where +module Language.Java.Classfile.Extract (Extract(), bytes) where import Data.ByteString.Lazy (ByteString) +import qualified Data.ByteString.Lazy as ByteString data Extract a = Extract (Continuation a) @@ -28,6 +29,16 @@ instance Applicative Extract where Fail -> Fail +-- | Get a specified count of bytes. Fail if there are not enough bytes available. + +bytes :: Word -> Extract ByteString +bytes count = Extract $ \ input -> let + count' = fromIntegral count + (bs, rest) = ByteString.splitAt count' input + in if ByteString.length bs /= count' + then Fail + else Done rest bs + {- It seems I cannot define a lawful monad instance instance Monad Extract where diff --git a/src/Language/Java/Classfile/Extractable.hs b/src/Language/Java/Classfile/Extractable.hs index 16ff016..43ad37d 100644 --- a/src/Language/Java/Classfile/Extractable.hs +++ b/src/Language/Java/Classfile/Extractable.hs @@ -1,4 +1,11 @@ -module M () where +{-# LANGUAGE InstanceSigs #-} +module Language.Java.Classfile.Extractable () where +import Language.Java.Classfile.Extract (Extract, bytes) +import Data.Word (Word8, Word16, Word32) +import qualified Data.ByteString.Lazy as ByteString +import Data.ByteString.Lazy (ByteString) +import Data.Bits (Bits(shiftL, (.|.))) +import GHC.Generics (U1 (U1)) class Extractable a where @@ -6,4 +13,19 @@ class Extractable a where instance Extractable Word8 where extract :: Extract Word8 - extract = _ + extract = ByteString.head <$> bytes 1 + +instance Extractable Word16 where + extract :: Extract Word16 + extract = build <$> bytes 2 + +instance Extractable Word32 where + extract :: Extract Word32 + extract = build <$> bytes 4 + +build :: (Bits a, Num a) => ByteString -> a +build = ByteString.foldl' shiftOr 0 + +shiftOr :: (Bits a1, Num a1) => a1 -> Word8 -> a1 +shiftOr word appendix = shiftL word 8 .|. fromIntegral appendix + diff --git a/src/Language/Java/Classfile/FromBigEndian.hs b/src/Language/Java/Classfile/FromBigEndian.hs new file mode 100644 index 0000000..6e269b1 --- /dev/null +++ b/src/Language/Java/Classfile/FromBigEndian.hs @@ -0,0 +1,21 @@ +{-# LANGUAGE InstanceSigs #-} +module Language.Java.Classfile.FromBigEndian () where +import Data.Word (Word16, byteSwap16, Word32, byteSwap32) +import GHC.ByteOrder (ByteOrder(..)) +import qualified GHC.ByteOrder as GHC + +class FromBigEndian a where + fromBigEndian :: a -> a + +instance FromBigEndian Word16 where + fromBigEndian :: Word16 -> Word16 + fromBigEndian = case GHC.targetByteOrder of + LittleEndian -> byteSwap16 + BigEndian -> id + +instance FromBigEndian Word32 where + fromBigEndian :: Word32 -> Word32 + fromBigEndian = case GHC.targetByteOrder of + LittleEndian -> byteSwap32 + BigEndian -> id +