#!/bin/sh

ddq()
{
	dd "$@" 2> /dev/null
}

store()
{
	n=$2; for i in $(seq 8 8 32); do
		printf '\\\\x%02X' $(($n & 255))
		n=$(($n >> 8))
	done | xargs echo -en | ddq bs=1 conv=notrunc of="$3" seek=$(($1))
}

get()
{
	echo $(od -j $(($1)) -N ${3:-4} -t u${3:-4} -An "$2")
}

end()
{
	echo $(( $(get 0x1F1 "$1" 1)*32 +($(get 0x1F4 "$1") +31 +${2:-1})&-${2:-1} ))
}

if [ ! -s "$1" -a -z "$4" ]; then
	p=$(basename "$0")
	cat <<EOT
Usage: $p kernel [initrd] [@]
or: $p menufile "menu title" file1 "menu entry 1" ...
EOT
elif [ -n "$4" ]; then
	out="$1"
	uudecode <<EOT | gunzip > "$out"
begin-base64 644 -
H4sIAOtonFkCA/uzn2FCuHjnH8OTgbsrGPpuHjUXY9/IFv55qdox1x/2fTf7
2XvcmXYcYA+Ql2M3fOu6g5nhrMAWxp0MAmcF9hUxvmBifMHC2Plyu8LaR8zT
t9t1/Hjxk2Ht2mYbhtI3+9IYNyg8Ytpg9+IZg5zhgb4b+3JYjrEs28HLaKVS
wn1WrOTrjLNinWYZNfI2vCUCDX88Spl9S+Y5NvwJeDjj9fTHhi9aGQJ3MDKd
FY4sauu8717C11j7d3pE6bfG2v+OL0rfy4X/6mr/yCgmL8Zu+H+64W3300D3
rOE4UPp77fTOn3sZGR53vUhheOHAsHY62JS1YUU607TtnZ0b/rOUft/O5Fci
1vnC0eJgHcdGRoNzpUz/joKVFd/ZF8XI+b+EeV8c4wsVhrjXG3c6MOxmYAJK
drzzPCtc9K3zbOePbx87Hv47eOGFwLeOo4dBlrJs4DJh383OsIXvrADQO5+L
Xx1W8PdmUHAqys9OzWNwzkhNzlbITU3JTGQYaFDECCKDczJDEqtCVwEAm9J3
EgACAAA=
====
EOT
	pos=$(get 0x1F2 "$out")
	[ $(get $(($pos - 3)) "$out") -eq 24937 ] && crc=2 || crc=0
	echo -en "$2\0" | ddq bs=1 of="$out" seek=$pos conv=notrunc
	pos=$(($pos+${#2}+1))
	shift 2
	free=$((0x1F1 - 2 - $pos - $crc))
	while [ -n "$2" -a $free -ge ${#2} ]; do
		echo "$((($(stat -c "%s" "$1")+511)/512)) $1 $2"
		shift 2
	done | awk '
BEGIN { i=0 } { sz[i]=$1; fn[i]=$2; sub(".*"$2,""); me[i++]=$0 }
END {
  for (m=0, l=p=1; m<i; m++) {
    for (s=100000, j=0; j<i; j++) if (!lc[j] && sz[j]<s) s=sz[k=j];
    f2[m] = fn[k]; s2[m] = s; lc[k]=l; l+=s; l2[m]=p; p+=sz[m]
  }
  for (j=0; j<i; j++)
    print sz[j] " " lc[j] " " fn[j] " " s2[j] " " l2[j] " " f2[j] " " me[j]
}' |	while read s p file s2 p2 file2 entry ; do
		[ -z "$SORT_MENU" ] && file2=$file && s2=$s && p=$p2
		x="$(printf '\\x%02x\\x%02x' $(($p % 256)) $(($p / 256)) )"
		echo -en "$x$entry\0" | ddq bs=1 of="$out" seek=$pos conv=notrunc
		pos=$(($pos+2+${#entry}+1))
		cat "$file2" /dev/zero | ddq bs=512 count=$s2 >> "$out"
		if [ $crc -ne 0 ]; then
			x=$(cat "$file" /dev/zero | ddq bs=512 count=$s | od -v \
			    -t u2 -w2 -An|awk '{i+=$0} END {print (i % 65536)}')
			x="$(printf '\\x%02x\\x%02x' $(($x % 256)) $(($x / 256)) )"
			echo -en "$x" | ddq bs=1 of="$out" seek=$pos conv=notrunc
			pos=$(($pos+2))
			x="$(printf '\\x%02x\\x%02x' $(($s % 256)) $(($s / 256)) )"
			echo -en "$x" | ddq bs=1 of="$out" seek=$pos conv=notrunc
			pos=$(($pos+2))
		fi
		shift 2
	done
elif [ -s "$2" ]; then
	base_initrd=$((0x00300000))
	size_initrd=$(stat -c %s "$2")
	[ $(($base_initrd + $size_initrd)) -gt $((0x1000000)) ] &&
	base_initrd=$((0x01400000))
	[ "$3" ] && base_initrd=$(($3))
	printf "initrd @%X %X\n" $base_initrd $size_initrd
	store 0x218 $base_initrd "$1"
	store 0x21C $size_initrd "$1"
	ddq bs=16 seek=$(end "$1" 32) of="$1" if="$2"
	ls -l "$1"
else
	if [ $(get 0x1F1 "$1" 1) -eq 0 ]; then
		menu=$(get 0x1F2 "$1")
		[ $(get $(($menu -3)) "$1" 2) -eq 24937 ] && skip=4 || skip=0
		ddq bs=1 skip=$menu count=$((0x1F3 - $menu)) if="$1" | \
		od -v -t u1 -w1 -An | awk -vx=$skip '{
	if (--skip >= 0) next
	if (--bytes < 0) {
		if ($1 == 0) {
			if (mul > 0) {
				if (sector == 0) exit
				skip=x; print sector " " s
			}
			s=""; sector=0; mul=1; bytes=2
		}
		else { c=sprintf("%c",$1); s=s c }
	}
	else { sector += $0*mul; mul *= 256 }
}' |		while read s name; do
			cnt=$(get $(($s*512 + 0x1F4)) "$1")
			cnt=$(($cnt+32*(1+$(get $(($s*512 + 0x1F1)) "$1" 1))))
			x=0
			if [ $(get $(($s*512 + 0x202)) "$1" 2) -eq 25672 ]; then
				x=$(get $(($s*512 + 0x21C)) "$1")
				[ $x -ne 0 ] && x=$(((($cnt+31)/32)*512+$x)) &&
				cnt=$((($x+15)/16))
			fi
			ddq bs=16 skip=$((32*$s)) count=$cnt if="$1" of="$name"
			[ $x -ne 0 ] && ddq bs=1 seek=$x count=0 of="$name"
 			ls -l "$name"
		done
	else
		base_initrd=$(get 0x218 "$1")
		size_initrd=$(get 0x21C "$1")
		[ $base_initrd -ne 0 ] &&
		printf "initrd @%X\n" $base_initrd &&
		ddq bs=1 skip=$(($(end "$1" 32) * 16)) count=$size_initrd \
			if="$1" of=initrd && ls -l initrd
		store 0x218 0 "$1"
		store 0x21C 0 "$1"
		ddq bs=16 count=0 seek=$(end "$1") of="$1"
		ls -l "$1"
	fi
fi
true
