Packages
smppex
2.2.9
3.3.0
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
retired
3.1.0
retired
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.4.0
2.3.3
2.3.2
2.3.1
2.3.0
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.0
2.0.1
2.0.0
1.0.1
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
SMPP 3.4 protocol and framework implemented in Elixir
Current section
Files
Jump to
Current section
Files
lib/smppex/protocol/unpack.ex
defmodule SMPPEX.Protocol.Unpack do
@moduledoc false
alias SMPPEX.Protocol.Unpack.Helpers
@null 0
@unexpected_data_end "Unexpected end of data"
@invalid_c_octet_string_format "C-Octet String: wrong format"
@invalid_fixed_c_octet_string "C-Octet String(fixed): invalid"
@invalid_c_octet_string_no_terminator "C-Octet String(var): null terminator not found"
@type unpack_error_result :: {:error, any}
@type integer_size :: 1 | 2 | 4
@spec integer(binary, integer_size) :: unpack_error_result | {:ok, non_neg_integer, binary}
def integer(bin, size) when (size == 1 or size == 2 or size == 4) and is_binary(bin) do
integer_bit_size = size * 8
case bin do
<<int::big-unsigned-integer-size(integer_bit_size), rest::binary>> -> {:ok, int, rest}
_ -> {:error, @unexpected_data_end}
end
end
@type length_spec :: {:fixed, pos_integer} | {:max, pos_integer}
@type kind :: :ascii | :hex | :dec
@type c_octet_string_result :: unpack_error_result | {:ok, binary, binary}
@spec c_octet_string(binary, length_spec) :: c_octet_string_result
def c_octet_string(bin, length_spec) when is_binary(bin) do
c_octet_string(bin, length_spec, :ascii)
end
@spec c_octet_string(binary, length_spec, kind) :: c_octet_string_result
def c_octet_string(bin, {:fixed, len}, kind) when len >= 1 and is_binary(bin) do
str_length = len - 1
case bin do
<<@null::size(8), rest::binary>> ->
{:ok, "", rest}
<<str::binary-size(str_length), @null::size(8), rest::binary>> ->
case valid_kind?(str, kind) do
true -> {:ok, str, rest}
false -> {:error, @invalid_c_octet_string_format}
end
<<_::binary-size(len), _::binary>> ->
{:error, @invalid_fixed_c_octet_string}
_ ->
{:error, @unexpected_data_end}
end
end
def c_octet_string(bin, {:max, len}, kind) when len >= 1 and is_binary(bin) do
case Helpers.take_until(bin, @null, len) do
{str, rest} ->
case valid_kind?(str, kind) do
true -> {:ok, str, rest}
false -> {:error, @invalid_c_octet_string_format}
end
:not_found ->
{:error, @invalid_c_octet_string_no_terminator}
end
end
@spec valid_kind?(binary, kind) :: boolean
defp valid_kind?(_str, :ascii), do: true
defp valid_kind?(str, :dec), do: Helpers.dec?(str)
defp valid_kind?(str, :hex), do: Helpers.hex?(str)
@spec octet_string(binary, non_neg_integer) :: unpack_error_result | {:ok, binary, binary}
def octet_string(bin, len) when len >= 0 and is_binary(bin) do
case bin do
<<str::binary-size(len), rest::binary>> -> {:ok, str, rest}
_ -> {:error, @unexpected_data_end}
end
end
@type parsed_tlv :: {non_neg_integer, binary}
@spec tlv(binary) :: unpack_error_result | {:ok, parsed_tlv, binary}
def tlv(bin) when byte_size(bin) < 4 do
{:error, @unexpected_data_end}
end
def tlv(<<
tag::big-unsigned-integer-size(16),
len::big-unsigned-integer-size(16),
value_and_rest::binary
>>) do
case value_and_rest do
<<value::binary-size(len), rest::binary>> -> {:ok, {tag, value}, rest}
_ -> {:error, @unexpected_data_end}
end
end
end