Current section
Files
Jump to
Current section
Files
lib/tlv8_decoder.ex
defmodule TLV8Decoder do
@moduledoc false
def decode(input) do
# The decoder accumlates items in reverse order for speed, then reorders them at the end
Enum.reverse(decode(input, [], nil))
end
defp decode(input, acc, last_tlv8) do
{type, value, remainder} = decode_type_value(input)
{pending_tlv8, completed_tlv8} = generate_tlv8(type, value, last_tlv8)
accumulate_tlv8(acc, pending_tlv8, completed_tlv8, remainder)
end
defp decode_type_value(<<type::unsigned-big-integer-size(8), length::unsigned-big-integer-size(8), valueremainder::binary>>) do
if byte_size(valueremainder) >= length do
<<value::binary-size(length), remainder::binary>> = valueremainder
{type, value, remainder}
else
{ :invalid_tlv8, :invalid_tlv8, <<>> }
end
end
defp decode_type_value(_input) do
{ :invalid_tlv8, :invalid_tlv8, <<>> }
end
defp generate_tlv8(type, value, last_tlv) when type == :invalid_tlv8 or value == :invalid_tlv8 do
# The type or value is invalid so we cannot generate a TLV
{:invalid_tlv8, last_tlv}
end
defp generate_tlv8(type, value, last_tlv) when not is_nil(last_tlv) do
if (last_tlv.type == type) do
# This TLV8 is a continuation of the last TLV8, so add its value to the last TLV8
{%TLV8{type: type, value: last_tlv.value <> value}, nil}
else
# This TLV8 is not a continuation of the last TLV8, so return the last one as complete
{%TLV8{type: type, value: value}, last_tlv}
end
end
defp generate_tlv8(type, value, last_tlv) when is_nil(last_tlv) do
# There is no last TLV8 to consider, so just generate a new TLV8
{%TLV8{type: type, value: value}, nil}
end
defp accumulate_tlv8(acc, pending_tlv8, completed_tlv8, remainder) when byte_size(remainder) > 0 and not is_nil(completed_tlv8) do
# There is a completed TLV so add it to the accumulator, then process the remaining bytes
decode(remainder, [ completed_tlv8 | acc ], pending_tlv8)
end
defp accumulate_tlv8(acc, pending_tlv8, _completed_tlv8, remainder) when byte_size(remainder) > 0 do
# There is no completed TLV so don't add anything to the accumulator, but there are remaining bytes to process
decode(remainder, acc, pending_tlv8)
end
defp accumulate_tlv8(acc, pending_tlv8, completed_tlv8, _remainder) when not is_nil(completed_tlv8) do
# There is a completed TLV so add it to the accumulator, and then add the current TLV too because there are no more bytes to process
[ pending_tlv8 | [ completed_tlv8 | acc ]]
end
defp accumulate_tlv8(acc, pending_tlv8, _completed_tlv8, _remainder) do
# There is no completed TLV, but there are no more bytes to process so add the current TLV
[ pending_tlv8 | acc ]
end
end