#!/usr/bin/env python3 """a leb128 decoder,encoder""" import argparse def devibytes(val): """A custom arg handler, just to handle bytes in hex format""" ret = [] for byte in val.split(","): ret.append(int(byte, 16)) return bytes(ret) def LEB128UnsignedDecode(bytelist): """LEB128 unsiged decoder""" result = 0 shift = 0 for byte in bytelist: result |= (byte & 0x7F) << shift if (byte & 0x80) == 0: break shift += 7 return result def LEB128SignedDecode(bytelist): """LEB128 signed decoder""" result = 0 shift = 0 for byte in bytelist: result |= (byte & 0x7F) << shift last_byte = byte shift += 7 if (byte & 0x80) == 0: break if last_byte & 0x40: result |= -(1 << shift) return result def LEB128UnsignedEncode(int_val): """LEB128 signed encoder""" if int_val < 0: raise Exception("value must not be negative") if int_val == 0: return bytes([0]) byte_array = bytearray() while int_val: byte = int_val & 0x7F byte_array.append(byte | 0x80) int_val >>= 7 byte_array[-1] ^= 0x80 return byte_array def LEB128SignedEncode(int_val): """LEB128 signed encoder""" byte_array = bytearray() while True: byte = int_val & 0x7F byte_array.append(byte | 0x80) int_val >>= 7 if (int_val == 0 and byte & 0x40 == 0) or ( int_val == -1 and byte & 0x40 ): byte_array[-1] ^= 0x80 break return byte_array # pylint: disable=too-few-public-methods class Argparser: """CLI args""" def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--se", type=int, help="leb128 signed encode") parser.add_argument("--ue", type=int, help="leb128 unsigned encode") parser.add_argument( "--sd", type=devibytes, help="leb128 signed decode. pass a string like ef1289.", ) parser.add_argument( "--ud", type=devibytes, help="leb128 unsigned decode. pass a string like ef1290", ) self.args = parser.parse_args() def main(): """entrypoint""" argparser = Argparser() # here if argparser.args.se: res = LEB128SignedEncode(argparser.args.se) for byte in res: print(format(byte, "02x"), end=" ") print() if argparser.args.ue: res = LEB128UnsignedEncode(argparser.args.ue) for byte in res: print(format(byte, "02x"), end=" ") print() if argparser.args.sd: print(LEB128SignedDecode(argparser.args.sd)) if argparser.args.ud: print(LEB128UnsignedDecode(argparser.args.ud)) if __name__ == "__main__": main()