module Octane.Type.Primitive.PCString (PCString(..)) where
import qualified Data.Binary.Get as Binary
import qualified Data.Binary.Put as Binary
import qualified Data.ByteString.Char8 as BS8
import qualified Data.Char as Char
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Encoding
import Octane.Core
import Octane.Type.Primitive.Word32LE
newtype PCString = PCString
{ getPCString :: Text
} deriving (Eq, Generic, NFData, Ord, Show)
instance Binary PCString where
get = do
(Word32LE size) <- get
string <- if size == 0
then fail ("invalid PCString size " ++ show size)
else if size < 0
then do
let actualSize = 2 * negate size
bytes <- Binary.getByteString (fromIntegral actualSize)
bytes & Encoding.decodeUtf16LE & return
else do
bytes <- Binary.getByteString (fromIntegral size)
bytes & Encoding.decodeLatin1 & return
string & Text.dropEnd 1 & PCString & return
put (PCString string) = do
let cString = Text.snoc string '\NUL'
let size = cString & Text.length & fromIntegral
if Text.all Char.isLatin1 cString
then do
size & Word32LE & put
cString & encodeLatin1 & Binary.putByteString
else do
size & negate & Word32LE & put
cString & Encoding.encodeUtf16LE & Binary.putByteString
encodeLatin1 :: Text -> ByteString
encodeLatin1 text = text & Text.unpack & BS8.pack