hex to base64 without using batteries and and excessive generators in python
BT_ZERO, BT_NINE, BT_A, BT_F, BT_Z = ord(
'0'), ord('9'), ord('A'), ord('F'), ord('Z')
BT_LIL_A, BT_LIL_Z = ord('a'), ord('z')
BT_CHR62, BT_CHR63 = ord('+'), ord('/')
BT_PAD = ord('=')
B64_BYTES = list(range(BT_A, BT_Z + 1)) +\
list(range(BT_LIL_A, BT_LIL_Z + 1)) +\
list(range(BT_ZERO, BT_NINE + 1)) + \
[BT_CHR62, BT_CHR63]
# print(''.join([chr(x) for x in B64_BYTES])) # make string
def hex_digit_conv(x):
if x > BT_A:
return (x - BT_A) + 10
else:
return x - BT_ZERO
def nibble_pairs(ingen):
pair = []
watchdog = None
for count, val in enumerate(ingen):
watchdog = count
pair.append(val)
if (count & 1) == 1: # odd check (conceptualy it's even if we weren't counting up from zero)
yield pair
pair = []
if (watchdog & 1) == 0:
raise IndexError("uneven number of digits")
def hex_bytes_2_bytes_gen(hb):
hb = (x for x in hb.upper() if x > BT_ZERO - 1 and x <
BT_NINE + 1 or x > BT_A - 1 and x < BT_F + 1)
btgen = (hex_digit_conv(pair[0]) * 16 +
hex_digit_conv(pair[1]) for pair in nibble_pairs(hb))
# print(''.join([chr(x) for x in btgen])) # make string
return btgen
def slice_n_gen(ingen, n):
""" How to reimpliment itertools.islice for no reason"""
group = []
count = 0
countmod = 0
for val in ingen:
count += 1
countmod = count % n
if countmod == 0:
group += [val]
yield group
group = []
else:
group += [val]
if countmod != 0:
yield group
def hex2b64(hexbytes):
return bytes2b64(hex_bytes_2_bytes_gen(hexbytes))
def bytes2b64(inbytes):
bytegrouping = 3
for bits in slice_n_gen(inbytes, bytegrouping):
chunk = []
extra = bytegrouping - len(bits)
total = (bits[0] << 16)
if extra < 2:
total |= (bits[1] << 8)
if extra < 1:
total |= (bits[2])
nchrs = [(total >> 18) & 63, (total >> 12) &
63, (total >> 6) & 63, total & 63]
if extra == 0:
chunk += [nchrs[0], nchrs[1], nchrs[2], nchrs[3]]
elif extra == 1:
chunk += [nchrs[0], nchrs[1], nchrs[2], None]
elif extra == 2:
chunk += [nchrs[0], nchrs[1], None, None]
for c in map(lambda x: BT_PAD if x is None else B64_BYTES[x], chunk):
yield c
def main():
import sys
arg = sys.argv[1]
r = ''.join(chr(x) for x in hex2b64(bytes(arg, 'latin-1')))
print(r)
def test1():
import pprint
import codecs
for i in range(0, 9):
pprint.pprint([x for x in slice_n_gen(range(0, i), 3)])
expected = """
[]
[[0]]
[[0, 1]]
[[0, 1, 2]]
[[0, 1, 2], [3]]
[[0, 1, 2], [3, 4]]
[[0, 1, 2], [3, 4, 5]]
[[0, 1, 2], [3, 4, 5], [6]]
[[0, 1, 2], [3, 4, 5], [6, 7]]
"""
def sanity_check(h_bt_str):
print("______________")
print("Sanity Check:")
r = codecs.encode(codecs.decode(h_bt_str, 'hex'),
'base64').decode("latin-1")
print(r)
print("Result:")
r = ''.join(map(chr, hex2b64(bytes(h_bt_str))))
print(r)
print("---------------")
hexvals = [
b"49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6573206d757368726f6f6d21",
b"49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"]
testvals = ["hello", "hello!", "hello!!", "hello!!!", "hello!!!?", ]
testvals = [codecs.encode(x.encode('latin-1'), 'hex') for x in testvals]
testvals += hexvals
for x in testvals:
# if len(x) % 3 == 2:
# import ipdb; ipdb.set_trace()
sanity_check(x)
if __name__ == '__main__':
main()
# test1()