+#!/bin/bash
+
+set -u
+
+filename=${1:-p1_16.txt}
+debug=${2:-0}
+
+exec 3<"${filename}"
+
+declare -A hex_to_binary=( [0]="0000" [1]="0001" [2]="0010" [3]="0011" [4]="0100" [5]="0101" [6]="0110" [7]="0111" [8]="1000" [9]="1001" [A]="1010" [B]="1011" [C]="1100" [D]="1101" [E]="1110" [F]="1111" )
+
+read -u 3 hex_string
+
+declare -g __packets=""
+for (( a=0; a<${#hex_string}; a++ )); do
+ __packets+=${hex_to_binary[${hex_string:$a:1}]}
+done
+
+declare -g __versions_total=0
+
+declare __packet_offset=0
+
+if [ $debug == "0" ]; then
+ echo_verbose() { true; }
+else
+ echo_verbose() { echo "$@" >&2; }
+fi
+
+parse_version() {
+ declare -g __packet_version=$((2#${__packets:$__packet_offset:3}))
+ ((__packet_offset+=3))
+ echo_verbose "Packet version: $__packet_version"
+}
+
+parse_type() {
+ declare -g __packet_type=$((2#${__packets:$__packet_offset:3}))
+ ((__packet_offset+=3))
+ echo_verbose "Packet type: $__packet_type"
+}
+
+parse_literal() {
+ local keep_going=${__packets:$__packet_offset:1}
+ local binary_value=""
+ ((__packet_offset+=1))
+ while [ $keep_going -eq 1 ]; do
+ binary_value+=${__packets:$__packet_offset:4}
+ ((__packet_offset+=4))
+ keep_going=${__packets:$__packet_offset:1}
+ ((__packet_offset+=1))
+ done
+ # if we're here, we're on to the last group
+ binary_value+=${__packets:$__packet_offset:4}
+ ((__packet_offset+=4))
+ declare -g __packet_literal=$((2#$binary_value))
+ echo_verbose "Packet literal: $__packet_literal"
+}
+
+parse_operator() {
+ local len_type=$((2#${__packets:$__packet_offset:1}))
+ ((__packet_offset+=1))
+
+ case $len_type in
+ 0)
+ __packets_length=$((2#${__packets:$__packet_offset:15}))
+ ((__packet_offset+=15))
+ ;;
+ 1)
+ __packets_count=$((2#${__packets:$__packet_offset:11}))
+ ((__packet_offset+=11))
+ ;;
+ esac
+}
+
+parse_packets() {
+ # we'll first need the version and the type, so grab those
+ local pversion
+ local ptype
+
+ while [ $__packet_offset -lt ${#__packets} ]; do
+ parse_version
+ parse_type
+ version=$__packet_version
+ ptype=$__packet_type
+
+ ((__versions_total+=$version))
+
+ echo_verbose "Remaining: ${__packets:$__packet_offset}"
+
+ case $ptype in
+ 4)
+ parse_literal
+ ;;
+ *)
+ parse_operator
+ ;;
+ esac
+
+ if [ $(($__packet_offset+7)) -ge ${#__packets} ]; then
+ break
+ fi
+ done
+}
+
+parse_packets
+
+echo "Total: $__versions_total"