Skip to content

Commit e213b2d

Browse files
authored
Merge pull request #4 from commercialhaskell/fix1
Fix #1 Enforce that the Word64 values used are little-endian.
2 parents ec6f717 + 08d19aa commit e213b2d

File tree

1 file changed

+20
-4
lines changed

1 file changed

+20
-4
lines changed

src/Data/StaticBytes.hs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import qualified Data.Vector.Unboxed.Base as VU
3838
import Foreign.ForeignPtr ( ForeignPtr, withForeignPtr )
3939
import Foreign.Ptr ( Ptr, castPtr )
4040
import Foreign.Storable ( Storable (..) )
41+
import GHC.ByteOrder ( ByteOrder (..), targetByteOrder )
4142
import RIO hiding ( words )
4243
import System.IO.Unsafe ( unsafePerformIO )
4344

@@ -79,27 +80,31 @@ class DynamicBytes dbytes where
7980
lengthD :: dbytes -> Int
8081
-- Yeah, it looks terrible to use a list here, but fusion should kick in
8182
withPeekD :: dbytes -> ((Int -> IO Word64) -> IO a) -> IO a
83+
-- ^ This assumes that the Word64 values are all little-endian.
8284
-- | May throw a runtime exception if invariants are violated!
8385
fromWordsD :: Int -> [Word64] -> dbytes
86+
-- ^ This assumes that the Word64 values are all little-endian.
8487

8588
fromWordsForeign ::
8689
(ForeignPtr a -> Int -> b)
8790
-> Int
8891
-> [Word64]
92+
-- ^ The Word64 values are assumed to be little-endian.
8993
-> b
9094
fromWordsForeign wrapper len words0 = unsafePerformIO $ do
9195
fptr <- B.mallocByteString len
9296
withForeignPtr fptr $ \ptr -> do
9397
let loop _ [] = pure ()
9498
loop off (w:ws) = do
95-
pokeElemOff (castPtr ptr) off w
99+
pokeElemOff (castPtr ptr) off (fromLE64 w)
96100
loop (off + 1) ws
97101
loop 0 words0
98102
pure $ wrapper fptr len
99103

100104
withPeekForeign ::
101105
(ForeignPtr a, Int, Int)
102106
-> ((Int -> IO Word64) -> IO b)
107+
-- ^ The Word64 values are assumed to be little-endian.
103108
-> IO b
104109
withPeekForeign (fptr, off, len) inner =
105110
withForeignPtr fptr $ \ptr -> do
@@ -113,7 +118,7 @@ withPeekForeign (fptr, off, len) inner =
113118
let w64' = shiftL (fromIntegral w8) (i * 8) .|. w64
114119
loop w64' (i + 1)
115120
loop 0 0
116-
| otherwise = peekByteOff ptr (off + off')
121+
| otherwise = toLE64 <$> peekByteOff ptr (off + off')
117122
inner f
118123

119124
instance DynamicBytes B.ByteString where
@@ -133,7 +138,7 @@ instance word8 ~ Word8 => DynamicBytes (VP.Vector word8) where
133138
let loop _ [] =
134139
VP.Vector 0 len <$> BA.unsafeFreezeByteArray ba
135140
loop i (w:ws) = do
136-
BA.writeByteArray ba i w
141+
BA.writeByteArray ba i (fromLE64 w)
137142
loop (i + 1) ws
138143
loop 0 words0
139144
withPeekD (VP.Vector off len ba) inner = do
@@ -147,7 +152,8 @@ instance word8 ~ Word8 => DynamicBytes (VP.Vector word8) where
147152
let w64' = shiftL (fromIntegral w8) (i * 8) .|. w64
148153
loop w64' (i + 1)
149154
loop 0 0
150-
| otherwise = pure $ BA.indexByteArray ba (off + (off' `div` 8))
155+
| otherwise = pure $
156+
toLE64 $ BA.indexByteArray ba (off + (off' `div` 8))
151157
inner f
152158

153159
instance word8 ~ Word8 => DynamicBytes (VU.Vector word8) where
@@ -248,3 +254,13 @@ fromStatic ::
248254
=> sbytes
249255
-> dbytes
250256
fromStatic = fromWordsD (lengthS (Nothing :: Maybe sbytes)) . ($ []) . toWordsS
257+
258+
-- | Convert a 64 bit value in CPU endianess to little endian.
259+
toLE64 :: Word64 -> Word64
260+
toLE64 = case targetByteOrder of
261+
BigEndian -> byteSwap64
262+
LittleEndian -> id
263+
264+
-- | Convert a little endian 64 bit value to CPU endianess.
265+
fromLE64 :: Word64 -> Word64
266+
fromLE64 = toLE64

0 commit comments

Comments
 (0)