From 5723a9230864a7ed33866a667f66f3bbbeebefa1 Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Fri, 11 Jul 2025 17:50:29 +0200 Subject: [PATCH] feat: Extracting word types --- java-classfile.cabal | 1 + src/Language/Java/Classfile/Extract.hs | 13 +++++++++- src/Language/Java/Classfile/Extractable.hs | 26 ++++++++++++++++++-- src/Language/Java/Classfile/FromBigEndian.hs | 21 ++++++++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 src/Language/Java/Classfile/FromBigEndian.hs 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 +