Packages
smppex
3.2.1
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/pack.ex
defmodule SMPPEX.Protocol.Pack do
@moduledoc false
import Bitwise
alias SMPPEX.Protocol.Unpack.Helpers
@null 0
@null_str <<@null>>
@invalid_integer "Integer: invalid value"
@invalid_c_octet_string_value "C-Octet String: invalid value"
@invalid_c_octet_string_format "C-Octet String: invalid format"
@invalid_octet_string "Octet String: invalid value"
@invalid_tlv_tag "TLV: invalid tag"
@invalid_tlv_value "TLV: invalid value"
@type pack_ok_result :: {:ok, binary}
@type pack_error_result :: {:error, any}
@type pack_result :: pack_ok_result | pack_error_result
@type integer_size :: 1 | 2 | 4
@spec integer(any, integer_size) :: pack_result
def integer(nil, size), do: integer(0, size)
def integer(int, _size) when not is_integer(int), do: {:error, @invalid_integer}
def integer(int, size) when size == 1 or size == 2 or size == 4 do
integer_bit_size = size * 8
if int >= 0 and int < 1 <<< integer_bit_size do
{:ok, <<int::big-unsigned-integer-size(integer_bit_size)>>}
else
{:error, @invalid_integer}
end
end
@type kind :: :ascii | :hex | :dec
@type length_spec :: {:fixed, pos_integer} | {:max, pos_integer}
@spec c_octet_string(any, length_spec) :: pack_result
def c_octet_string(nil, length_spec), do: c_octet_string("", length_spec, :ascii)
def c_octet_string(str, length_spec), do: c_octet_string(str, length_spec, :ascii)
@spec c_octet_string(any, length_spec, kind) :: pack_result
def c_octet_string(str, _spec, _kind) when not is_binary(str),
do: {:error, @invalid_c_octet_string_value}
def c_octet_string(nil, length_spec, kind), do: c_octet_string("", length_spec, kind)
def c_octet_string(str, {:fixed, len}, kind) when is_integer(len) and len >= 1 do
c_octet_string_with_general_check(str, &(&1 == len), kind)
end
def c_octet_string(str, {:max, len}, kind) when is_integer(len) and len >= 1 do
c_octet_string_with_general_check(str, &(&1 <= len), kind)
end
@spec c_octet_string_with_general_check(binary, (integer -> boolean), kind) :: pack_result
defp c_octet_string_with_general_check(str, check, kind) when is_function(check) do
str_length = byte_size(str)
cond do
str == "" ->
{:ok, @null_str}
check.(str_length + 1) ->
if valid_kind?(str, kind) do
{:ok, str <> @null_str}
else
{:error, @invalid_c_octet_string_format}
end
true ->
{:error, @invalid_c_octet_string_value}
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) :: pack_result
def octet_string(str, _len) when not is_binary(str), do: {:error, @invalid_octet_string}
def octet_string(str, len) when is_integer(len) and len >= 0 do
if byte_size(str) == len do
{:ok, str}
else
{:error, @invalid_octet_string}
end
end
@spec tlv(integer, binary) :: pack_result
def tlv(_tag, str) when not is_binary(str), do: {:error, @invalid_tlv_value}
def tlv(tag, _str) when not is_integer(tag), do: {:error, @invalid_tlv_tag}
def tlv(tag, _str) when tag < 0, do: {:error, @invalid_tlv_tag}
def tlv(tag, _str) when tag > 65_535, do: {:error, @invalid_tlv_tag}
def tlv(_tag, str) when byte_size(str) >= 65_536, do: {:error, @invalid_tlv_value}
def tlv(tag, str) do
len = byte_size(str)
{:ok, <<tag::big-unsigned-integer-size(16), len::big-unsigned-integer-size(16), str::binary>>}
end
end