diff --git a/lib/elixir/lib/base.ex b/lib/elixir/lib/base.ex index a3c1f50dcb8..0d13460a308 100644 --- a/lib/elixir/lib/base.ex +++ b/lib/elixir/lib/base.ex @@ -657,10 +657,7 @@ defmodule Base do @spec valid64?(binary, ignore: :whitespace, padding: boolean) :: boolean def valid64?(string, opts \\ []) when is_binary(string) do pad? = Keyword.get(opts, :padding, true) - string |> remove_ignored(opts[:ignore]) |> validate64base!(pad?) - true - rescue - ArgumentError -> false + string |> remove_ignored(opts[:ignore]) |> validate64base?(pad?) end @doc """ @@ -754,110 +751,124 @@ defmodule Base do @spec url_valid64?(binary, ignore: :whitespace, padding: boolean) :: boolean def url_valid64?(string, opts \\ []) when is_binary(string) do pad? = Keyword.get(opts, :padding, true) - string |> remove_ignored(opts[:ignore]) |> validate64url!(pad?) - true - rescue - ArgumentError -> false + string |> remove_ignored(opts[:ignore]) |> validate64url?(pad?) end for {base, alphabet} <- [base: b64_alphabet, url: b64url_alphabet] do decode_name = :"decode64#{base}!" - validate_name = :"validate64#{base}!" + + validate_name = :"validate64#{base}?" + validate_main_name = :"validate_main64#{validate_name}?" + valid_char_name = :"valid_char64#{base}?" {min, decoded} = alphabet |> Enum.with_index() |> to_decode_list.() - defp unquote(validate_name)(<<>>, _pad?) do - true + defp unquote(validate_main_name)(<<>>), do: true + + defp unquote(validate_main_name)( + <> + ) do + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) and + unquote(valid_char_name)(c3) and + unquote(valid_char_name)(c4) and + unquote(valid_char_name)(c5) and + unquote(valid_char_name)(c6) and + unquote(valid_char_name)(c7) and + unquote(valid_char_name)(c8) and + unquote(validate_main_name)(rest) end + defp unquote(validate_name)(<<>>, _pad?), do: true + defp unquote(validate_name)(string, pad?) do segs = div(byte_size(string) + 7, 8) - 1 <> = string - - for <> do - unquote(decode_name)(c1) - unquote(decode_name)(c2) - unquote(decode_name)(c3) - unquote(decode_name)(c4) - unquote(decode_name)(c5) - unquote(decode_name)(c6) - unquote(decode_name)(c7) - unquote(decode_name)(c8) - end + main_valid? = unquote(validate_main_name)(main) case rest do + _ when not main_valid? -> + false + <> -> - unquote(decode_name)(c1) - unquote(decode_name)(c2) + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) <> -> - unquote(decode_name)(c1) - unquote(decode_name)(c2) - unquote(decode_name)(c3) + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) and + unquote(valid_char_name)(c3) <> -> - unquote(decode_name)(c1) - unquote(decode_name)(c2) - unquote(decode_name)(c3) - unquote(decode_name)(c4) + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) and + unquote(valid_char_name)(c3) and + unquote(valid_char_name)(c4) <> -> - unquote(decode_name)(c1) - unquote(decode_name)(c2) - unquote(decode_name)(c3) - unquote(decode_name)(c4) - unquote(decode_name)(c5) - unquote(decode_name)(c6) + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) and + unquote(valid_char_name)(c3) and + unquote(valid_char_name)(c4) and + unquote(valid_char_name)(c5) and + unquote(valid_char_name)(c6) <> -> - unquote(decode_name)(c1) - unquote(decode_name)(c2) - unquote(decode_name)(c3) - unquote(decode_name)(c4) - unquote(decode_name)(c5) - unquote(decode_name)(c6) - unquote(decode_name)(c7) + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) and + unquote(valid_char_name)(c3) and + unquote(valid_char_name)(c4) and + unquote(valid_char_name)(c5) and + unquote(valid_char_name)(c6) and + unquote(valid_char_name)(c7) <> -> - unquote(decode_name)(c1) - unquote(decode_name)(c2) - unquote(decode_name)(c3) - unquote(decode_name)(c4) - unquote(decode_name)(c5) - unquote(decode_name)(c6) - unquote(decode_name)(c7) - unquote(decode_name)(c8) + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) and + unquote(valid_char_name)(c3) and + unquote(valid_char_name)(c4) and + unquote(valid_char_name)(c5) and + unquote(valid_char_name)(c6) and + unquote(valid_char_name)(c7) and + unquote(valid_char_name)(c8) <> when not pad? -> - unquote(decode_name)(c1) - unquote(decode_name)(c2) + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) <> when not pad? -> - unquote(decode_name)(c1) - unquote(decode_name)(c2) - unquote(decode_name)(c3) + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) and + unquote(valid_char_name)(c3) <> when not pad? -> - unquote(decode_name)(c1) - unquote(decode_name)(c2) - unquote(decode_name)(c3) - unquote(decode_name)(c4) - unquote(decode_name)(c5) - unquote(decode_name)(c6) + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) and + unquote(valid_char_name)(c3) and + unquote(valid_char_name)(c4) and + unquote(valid_char_name)(c5) and + unquote(valid_char_name)(c6) <> when not pad? -> - unquote(decode_name)(c1) - unquote(decode_name)(c2) - unquote(decode_name)(c3) - unquote(decode_name)(c4) - unquote(decode_name)(c5) - unquote(decode_name)(c6) - unquote(decode_name)(c7) + unquote(valid_char_name)(c1) and + unquote(valid_char_name)(c2) and + unquote(valid_char_name)(c3) and + unquote(valid_char_name)(c4) and + unquote(valid_char_name)(c5) and + unquote(valid_char_name)(c6) and + unquote(valid_char_name)(c7) _ -> - raise ArgumentError, "incorrect padding" + false end end + @compile {:inline, [{valid_char_name, 1}]} + defp unquote(valid_char_name)(char) + when elem({unquote_splicing(decoded)}, char - unquote(min)) != nil, + do: true + + defp unquote(valid_char_name)(_char), do: false + defp unquote(decode_name)(char) do index = char - unquote(min)