packages feed

hbcd (empty) → 1.0

raw patch · 4 files changed

+149/−0 lines, 4 filesdep +Decimaldep +basedep +bytestringsetup-changed

Dependencies added: Decimal, base, bytestring, digits, split

Files

+ LICENSE.txt view
@@ -0,0 +1,20 @@+Copyright (c) 2012 Andrew Kay++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be+included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,5 @@+module Main where++import Distribution.Simple++main = defaultMain
+ hbcd.cabal view
@@ -0,0 +1,28 @@+Name:               hbcd+Version:            1.0+Synopsis:           Packed binary-coded decimal (BCD) serialization+Description:        A module containing packed binary-coded decimal (BCD) serialization+                    functions.  Packed BCD is commonly used to encode numbers in mainframe+                    datasets.+License:            MIT+License-File:       LICENSE.txt+Copyright:          Andrew Kay, 2012+Author:             Andrew Kay+Maintainer:         andrewjkay@gmail.com+Stability:          provisional+Category:           Data+Cabal-Version:      >= 1.6+Build-Type:         Simple++Library+  Exposed-Modules:  Data.BCD.Packed+  HS-Source-Dirs:   src+  Build-Depends:    base >= 4 && < 5,+                    bytestring >= 0.9.1.10,+                    Decimal >= 0.2.3,+                    digits >= 0.2,+                    split >= 0.1.4.3++Source-Repository head+  Type:             hg+  Location:         https://bitbucket.org/andrewjkay/hbcd
+ src/Data/BCD/Packed.hs view
@@ -0,0 +1,96 @@+{- |+Module      :  Data.BCD.Packed+Copyright   :  Andrew Kay, 2012+License:    :  MIT++Maintainer  :  andrewjkay@gmail.com+Stability   :  experimental+Portability :  portable++A module containing packed binary-coded decimal (BCD) serialization functions+-}++module Data.BCD.Packed (+	bytesRequired,+	packInteger,+	unpackInteger,+	packDecimal,+	unpackDecimal ) where++import Data.Word+import Data.Bits+import qualified Data.ByteString as BS+import Data.Decimal (Decimal, DecimalRaw(Decimal), decimalMantissa, decimalPlaces, roundTo)+import Data.Digits (digits)+import Data.List.Split (splitEvery)++-- | Pack two digits into a byte+packByte :: [Word8] -> Word8+packByte [m, l] = (shiftL m 4) .|. l++-- | Pack every pair of two digits into a byte resulting in a ByteString half as long as+--   the input+packBytes :: [Word8] -> BS.ByteString+packBytes bx = BS.pack $ map packByte $ splitEvery 2 bx++-- | Unpack two digits from a byte+unpackByte :: Word8 -> [Word8]+unpackByte b = [shiftR (b .&. 0xf0) 4, b .&. 0x0f]++-- | Unpack two digits from every byte in a ByteString resulting in a new ByteString twice+--   as long as the input+unpackBytes :: BS.ByteString -> BS.ByteString+unpackBytes bs = BS.concatMap (\b -> BS.pack $ unpackByte b) bs++-- | Encode the sign+encodeSign :: Integer -> Word8+encodeSign s+    | s < 0     = 0xd+    | otherwise = 0xc++-- | Decode the sign+decodeSign :: Word8 -> Integer+decodeSign n = case n of+    0xc -> 1+    0xd -> -1+    otherwise -> error "Unsupported sign value"++-- | Calculate the bytes required to store a number of digits+bytesRequired :: Int    -- ^ Number of digits (including leading zeros)+              -> Int    -- ^ Number of bytes required+bytesRequired l = ceiling (((fromIntegral l) + 1) / 2)++-- | Pack an Integer into a ByteString+packInteger :: Int              -- ^ Number of digits (including leading zeros)+            -> Integer          -- ^ Value +            -> BS.ByteString    -- ^ Packed BCD+packInteger l n+    | dsl > l = error "Number is to large for field"+    | otherwise = packBytes $ (replicate (nl - dsl - 1) 0) ++ ds ++ [s]+    where ds = map (\d -> fromIntegral d) (digits 10 (abs n))+          s = encodeSign (signum n)+          nl = (bytesRequired l) * 2+          dsl = length ds++-- | Unpack an Integer from a ByteString+unpackInteger :: BS.ByteString    -- ^ Packed BCD+              -> Integer          -- ^ Value+unpackInteger bs = n * s+    where ubs = unpackBytes bs+          n = BS.foldl (\n d -> (n * 10) + (toInteger d)) 0 $ BS.init ubs+          s = decodeSign $ BS.last ubs++-- | Pack a Decimal into a ByteString+packDecimal :: Int              -- ^ Number of digits (including leading zeros and decimal places)+            -> Word8            -- ^ Number of decimal places+            -> Decimal          -- ^ Value+            -> BS.ByteString    -- ^ Packed BCD+packDecimal l d n+    | (decimalPlaces n) > d = error "Decimal places to large for field"+    | otherwise = packInteger l $ decimalMantissa $ roundTo d n++-- | Unpack a Decimal from a ByteString+unpackDecimal :: Word8            -- ^ Number of decimal places+              -> BS.ByteString    -- ^ Packed BCD+              -> Decimal          -- ^ Value+unpackDecimal d bs = Decimal d $ unpackInteger bs