Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing a String with Data.Cereal or Data.Binary

Tags:

haskell

I am implementing a protocol that dictates that a string representing a password should be serialized to a fixed length, 10-byte field. I am using Data.Cereal to perform this task. Here's my most recent go at it:

padText :: Int -> Text -> Text
padText fieldLen = T.justifyLeft fieldLen '\NUL'

putPassword :: Putter Password
putPassword = put . TE.encodeUtf8 . padText 10

put on ByteStrings prepends an additional 8-byte chunk onto the front of what it is encoding making:

 runPut $ putPassword "Friend"

result in :

"\NUL\NUL\NUL\NUL\NUL\NUL\NUL\nFriend\NUL\NUL\NUL\NUL"

I don't want the extra chunk. Why is put behaving this way?

Does anyone know how to serialize only the 10 original bytes?

like image 700
Eric Avatar asked Jul 08 '12 03:07

Eric


2 Answers

I assume by "the extra chunk" you mean the first bit of "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\n. That is a 64 bit length field (notice it's value is 10) which is part of the Serialize definition for ByteString. Since you already have a bytestring after calling TE.encodeUtf8, I suggest you just use putByteString to avoid the length field (or putLazyByteString if you're importing a lazy text encoding module).

like image 114
Thomas M. DuBuisson Avatar answered Nov 07 '22 02:11

Thomas M. DuBuisson


As Thomas stated put on ByteStrings prepends the encoded length. Shown below is the actual instance:

instance Serialize B.ByteString where
    put bs = do put (B.length bs :: Int)
                putByteString bs
   ...

putByteString alone does not. The solution is to use putByteString:

putPassword :: Putter Password
putPassword = putByteString . TE.encodeUtf8 . padText 10
like image 26
Eric Avatar answered Nov 07 '22 02:11

Eric