import binascii
import json
import marshal
import sys
from types import CodeType


def parse_pyc_file(path):
    """
    path: str
        path to the file to parse
    """
    with open(path, "rb") as fp:
        header = fp.read(12)
        code = marshal.load(fp)
    bytecode_table = recursive_build_bytecode_table(code, {}, "")
    return binascii.hexlify(header).decode(), bytecode_table


def recursive_build_bytecode_table(code, table, parent_path):
    """
    Creates a table containing the bytecode of all code objects in the object

    code: CodeType
        The code to build the table from
    table: dict[str, str]
        Maps the "path" to the code object to its bytecode in hex encoded form
    parent_path:
        Path to the parent object. Joins the names of the parent objects in the code object tree.
    """
    path = parent_path + "::" + code.co_name
    table[path] = binascii.hexlify(code.co_code).decode()
    for const in code.co_consts:
        if isinstance(const, CodeType):
            recursive_build_bytecode_table(const, table, path)
    return table


if __name__ == "__main__":
    source_path = sys.argv[1]
    hex_header, bytecode_table = parse_pyc_file(source_path)
    d = {"header": hex_header, "bytecode_table": bytecode_table}
    print(json.dumps(d))
