{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} 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 -- | A length-prefixed null-terminated string. 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