#!/usr/bin/python3
def make_nibbles(dec, high):
"""Translates half of the dec digits into BCD nibble values
Arguments:
dec -- a bytes object of decimal digits. Length has to be a multiple of 2
high -- defines if the high or low nibble per byte should be calculated
Return value:
A bytes object representing the nibbles. The nibble that is not calculated
(per byte) is set to 0
"""
assert(not (len(dec) & 1))
# build a translation table from decimal digits to BCD nibble values
translate_from = b'0123456789'
bitshift = 4 if high else 0
translate_to = bytes(num << bitshift for num in range(10))
# TODO: This table should only be calculated once and reused afterwards
table = bytes.maketrans(translate_from, translate_to)
byteshift = 0 if high else 1
bytes_ = dec[byteshift::2]
return bytes_.translate(table)
def int2bcd(value):
"""Encodes an integer into a bytes object of packed BCD values"""
dec = bytes(str(value), 'ascii')
padded_len = (len(dec) + 1) >> 1 << 1
padded_dec = dec.rjust(padded_len, b'0')
nibbles_low = make_nibbles(padded_dec, high=False)
nibbles_high = make_nibbles(padded_dec, high=True)
return bytes(high | low for high, low
in zip(nibbles_high, nibbles_low))
def bcd2int(bcd):
lowmask = (1 << 4) - 1
bytevals = [(byte_ & lowmask) + 10 * (byte_ >> 4) for byte_ in bcd]
return sum(byteval * 100**pow_ for pow_, byteval
in enumerate(reversed(bytevals)))
def main():
value = int('42132801305034541=4101210013390'.replace("=", 'D'), 16)
bcd = int2bcd(value)
intval = bcd2int(bcd)
print("%d (%d) -> %s (%d) = %d" % (value, len(str(value)), bcd, len(bcd), intval))
if __name__ == '__main__':
main()
Comments