################################################################################
# Copyright (C) 2001 Ryan Finne <ryan@finnie.org>
# Copyright (C) 2002-2011 Travis Shirk <travis@pobox.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
################################################################################
from ..compat import intToByteString, BytesType, byteiter
[docs]def bytes2bin(bytes, sz=8):
'''Accepts a string of ``bytes`` (chars) and returns an array of bits
representing the bytes in big endian byte order. An optional max ``sz`` for
each byte (default 8 bits/byte) which can be used to mask out higher
bits.'''
if sz < 1 or sz > 8:
raise ValueError("Invalid sz value: %d" % sz)
'''
# I was willing to bet this implementation was gonna be faster, tis not
retval = []
for bite in bytes:
bits = [int(b) for b in bin(ord(bite))[2:].zfill(8)][-sz:]
assert(len(bits) == sz)
retval.extend(bits)
return retval
'''
retVal = []
for b in byteiter(bytes):
bits = []
b = ord(b)
while b > 0:
bits.append(b & 1)
b >>= 1
if len(bits) < sz:
bits.extend([0] * (sz - len(bits)))
elif len(bits) > sz:
bits = bits[:sz]
# Big endian byte order.
bits.reverse()
retVal.extend(bits)
return retVal
# Convert an array of bits (MSB first) into a string of characters.
[docs]def bin2bytes(x):
bits = []
bits.extend(x)
bits.reverse()
i = 0
out = b''
multi = 1
ttl = 0
for b in bits:
i += 1
ttl += b * multi
multi *= 2
if i == 8:
i = 0
out += intToByteString(ttl)
multi = 1
ttl = 0
if multi > 1:
out += intToByteString(ttl)
out = bytearray(out)
out.reverse()
out = BytesType(out)
return out
[docs]def bin2dec(x):
'''Convert ``x``, an array of "bits" (MSB first), to it's decimal value.'''
bits = []
bits.extend(x)
bits.reverse() # MSB
multi = 1
value = 0
for b in bits:
value += b * multi
multi *= 2
return value
[docs]def bytes2dec(bytes, sz=8):
return bin2dec(bytes2bin(bytes, sz))
[docs]def dec2bin(n, p=1):
'''Convert a decimal value ``n`` to an array of bits (MSB first).
Optionally, pad the overall size to ``p`` bits.'''
assert(n >= 0)
retVal = []
while n > 0:
retVal.append(n & 1)
n >>= 1
if p > 0:
retVal.extend([0] * (p - len(retVal)))
retVal.reverse()
return retVal
[docs]def dec2bytes(n, p=1):
return bin2bytes(dec2bin(n, p))
[docs]def bin2synchsafe(x):
'''Convert ``x``, a list of bits (MSB first), to a synch safe list of bits.
(section 6.2 of the ID3 2.4 spec).'''
n = bin2dec(x)
if len(x) > 32 or n > 268435456: # 2^28
raise ValueError("Invalid value: %s" % str(x))
elif len(x) < 8:
return x
bites = b""
bites += intToByteString((n >> 21) & 0x7f)
bites += intToByteString((n >> 14) & 0x7f)
bites += intToByteString((n >> 7) & 0x7f)
bites += intToByteString((n >> 0) & 0x7f)
bits = bytes2bin(bites)
assert(len(bits) == 32)
return bits