import os
import sys
import array
import struct
import argparse

CBF_MAGIC = -0x65432110
CBF_VERSION = 1
NAME_LEN = 64
BLOCK_SIZE = 0x20000
KERNEL_JUMP = 0x100000
IMAGE_PAD_SIZE = 4

KERNEL_LOAD = KERNEL_JUMP

buffer = ""
summary = ""

def pack_file(path):
	global summary
	global buffer

	name = path[path.rfind('/')+1:]
	if len(name) >= NAME_LEN:
		print(f"error: '{name}', name is too long")
		return False
	if not os.path.exists(path):
		print(f"error: path '{path}' not found")
		return False
	print(f"reading '{path}'")
	h = open(path, 'rb')
	data = h.read()
	h.close()
	size = len(data)
	rem = IMAGE_PAD_SIZE - (size % IMAGE_PAD_SIZE)
	print(f'size is {size}, adding {rem} bytes of padding')
	buffer = data + b'\xFF' * rem
	size = len(buffer)
	return size

def crc(buf):
	a = array.array ('L', buf)
	crc = 0;
	for c in a:
		crc = 1 + (crc ^ c)
	return crc

if __name__ == '__main__':
	parser = argparse.ArgumentParser('make_cbf')
	parser.add_argument('-k', '--kernel')
	parser.add_argument('-o', '--output')
	args = parser.parse_args()

	# Pack kernel image file
	size = pack_file(args.kernel);
	if not size:
		sys.exit(1)
	# MAGIC, VERSION, load, jump, len, crc, <data>, crc
	summary = struct.pack('lLLLL', CBF_MAGIC, CBF_VERSION, KERNEL_LOAD, KERNEL_JUMP, size)
	# Append crcs
	summary_crc = crc(summary)
	summary += struct.pack('L', summary_crc)
	buffer_crc = crc(buffer);
	buffer += struct.pack('L', buffer_crc)
	print("summary crc=%08x buffer crc=%08x buffer len=%08x" % (summary_crc, buffer_crc, size))

	# Pad out to block size
	rem = BLOCK_SIZE - ((len(summary) + len(buffer)) % BLOCK_SIZE)
	print(f'adding {rem} bytes of padding to cbf')
	pad = b'\xFF' * rem

	# Write out cbf
	h = open(args.output, "wb")
	h.write(summary)
	h.write(buffer)
	if rem > 0:
		h.write(pad)
	h.close()
