Packages
smppex
2.2.6
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/mandatory_fields_parser.ex
defmodule SMPPEX.Protocol.MandatoryFieldsParser do
@moduledoc false
alias SMPPEX.Protocol.Unpack
alias SMPPEX.Protocol.MandatoryFieldsSpecs
@spec parse(binary, MandatoryFieldsSpecs.fields_spec()) :: {:ok, map, binary} | {:error, any}
def parse(bin, spec), do: parse(bin, spec, Map.new())
@spec parse(binary, MandatoryFieldsSpecs.fields_spec(), map) ::
{:ok, map, binary} | {:error, any}
def parse(bin, [], parsed_fields) do
{:ok, parsed_fields, bin}
end
def parse(bin, [field_spec | rest_field_specs], parsed_fields) do
case parse_field(bin, field_spec, parsed_fields) do
{:ok, new_parsed_fields, rest} ->
parse(rest, rest_field_specs, new_parsed_fields)
{:error, error} ->
{:error, {"Error parsing field(s) #{inspect(field_spec)}", error}}
end
end
defp parse_field(bin, {field_name, spec}, parsed_fields) when is_tuple(spec) do
case read_value(bin, spec, parsed_fields) do
{:ok, value, rest} ->
{:ok, Map.put(parsed_fields, field_name, value), rest}
{:error, _} = err ->
err
end
end
defp parse_field(bin, {:case, cases}, parsed_fields) when is_list(cases) do
read_cases(bin, cases, parsed_fields)
end
defp read_value(bin, {:c_octet_string, {:max, n}}, parsed_fields) do
Unpack.c_octet_string(bin, {:max, expand(n, parsed_fields)})
end
defp read_value(bin, {:integer, n}, parsed_fields) do
Unpack.integer(bin, expand(n, parsed_fields))
end
defp read_value(bin, {:c_octet_string, {:fixed, n}}, parsed_fields) do
Unpack.c_octet_string(bin, {:fixed, expand(n, parsed_fields)})
end
defp read_value(bin, {:octet_string, n}, parsed_fields) do
Unpack.octet_string(bin, expand(n, parsed_fields))
end
defp read_value(bin, {:times, n, specs}, parsed_fields) do
case read_values(bin, {expand(n, parsed_fields), []}, specs, Map.new()) do
{:ok, values, rest} -> {:ok, Enum.reverse(values), rest}
{:error, _} = err -> err
end
end
defp read_values(bin, {0, values}, _specs, _parsed_fields), do: {:ok, values, bin}
defp read_values(bin, {n, values}, specs, parsed_fields) do
case parse(bin, specs, parsed_fields) do
{:ok, parsed_fields_inner, rest} ->
read_values(rest, {n - 1, [parsed_fields_inner | values]}, specs, parsed_fields)
{:error, _} = err ->
err
end
end
defp read_cases(_bin, [], _parsed_fields), do: {:error, "No cases left"}
defp read_cases(bin, [current_case | rest_cases], parsed_fields) do
{field, value, specs} = current_case
if expand(field, parsed_fields) == value do
parse(bin, specs, parsed_fields)
else
read_cases(bin, rest_cases, parsed_fields)
end
end
defp expand(n, _parsed_fields) when is_integer(n), do: n
defp expand(n, parsed_fields) when is_atom(n), do: parsed_fields[n]
end