| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- %%--------------------------------------------------------------------
- %% Original file taken from https://github.com/arcusfelis/binary2
- %% Copyright (c) 2016 Michael Uvarov
- %% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
- %%
- %% Licensed under the Apache License, Version 2.0 (the "License");
- %% you may not use this file except in compliance with the License.
- %% You may obtain a copy of the License at
- %%
- %% http://www.apache.org/licenses/LICENSE-2.0
- %%
- %% Unless required by applicable law or agreed to in writing, software
- %% distributed under the License is distributed on an "AS IS" BASIS,
- %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- %% See the License for the specific language governing permissions and
- %% limitations under the License.
- %%--------------------------------------------------------------------
- -module(emqx_utils_binary).
- %% Bytes
- -export([
- reverse/1,
- join/2,
- duplicate/2,
- suffix/2,
- prefix/2
- ]).
- %% Bits
- -export([
- union/2,
- subtract/2,
- intersection/2,
- inverse/1
- ]).
- %% Trimming
- -export([
- rtrim/1,
- rtrim/2,
- ltrim/1,
- ltrim/2,
- trim/1,
- trim/2
- ]).
- %% Parsing
- -export([bin_to_int/1]).
- %% Matching
- -export([optimize_patterns/1]).
- %% CoAP
- -export([join_path/1]).
- trim(B) -> trim(B, 0).
- ltrim(B) -> ltrim(B, 0).
- rtrim(B) -> rtrim(B, 0).
- rtrim(B, X) when is_binary(B), is_integer(X) ->
- S = byte_size(B),
- do_rtrim(S, B, X);
- rtrim(B, [_ | _] = Xs) when is_binary(B) ->
- S = byte_size(B),
- do_mrtrim(S, B, Xs).
- ltrim(B, X) when is_binary(B), is_integer(X) ->
- do_ltrim(B, X);
- ltrim(B, [_ | _] = Xs) when is_binary(B) ->
- do_mltrim(B, Xs).
- %% @doc The second element is a single integer element or an ordset of elements.
- trim(B, X) when is_binary(B), is_integer(X) ->
- From = ltrimc(B, X, 0),
- case byte_size(B) of
- From ->
- <<>>;
- S ->
- To = do_rtrimc(S, B, X),
- binary:part(B, From, To - From)
- end;
- trim(B, [_ | _] = Xs) when is_binary(B) ->
- From = mltrimc(B, Xs, 0),
- case byte_size(B) of
- From ->
- <<>>;
- S ->
- To = do_mrtrimc(S, B, Xs),
- binary:part(B, From, To - From)
- end.
- do_ltrim(<<X, B/binary>>, X) ->
- do_ltrim(B, X);
- do_ltrim(B, _X) ->
- B.
- %% multi, left trimming.
- do_mltrim(<<X, B/binary>> = XB, Xs) ->
- case ordsets:is_element(X, Xs) of
- true -> do_mltrim(B, Xs);
- false -> XB
- end;
- do_mltrim(<<>>, _Xs) ->
- <<>>.
- do_rtrim(0, _B, _X) ->
- <<>>;
- do_rtrim(S, B, X) ->
- S2 = S - 1,
- case binary:at(B, S2) of
- X -> do_rtrim(S2, B, X);
- _ -> binary_part(B, 0, S)
- end.
- %% Multiple version of do_rtrim.
- do_mrtrim(0, _B, _Xs) ->
- <<>>;
- do_mrtrim(S, B, Xs) ->
- S2 = S - 1,
- X = binary:at(B, S2),
- case ordsets:is_element(X, Xs) of
- true -> do_mrtrim(S2, B, Xs);
- false -> binary_part(B, 0, S)
- end.
- ltrimc(<<X, B/binary>>, X, C) ->
- ltrimc(B, X, C + 1);
- ltrimc(_B, _X, C) ->
- C.
- %% multi, left trimming, returns a count of matched bytes from the left.
- mltrimc(<<X, B/binary>>, Xs, C) ->
- case ordsets:is_element(X, Xs) of
- true -> mltrimc(B, Xs, C + 1);
- false -> C
- end;
- mltrimc(<<>>, _Xs, C) ->
- C.
- % This clause will never be matched.
- %do_rtrimc(0, _B, _X) ->
- % 0;
- do_rtrimc(S, B, X) ->
- S2 = S - 1,
- case binary:at(B, S2) of
- X -> do_rtrimc(S2, B, X);
- _ -> S
- end.
- do_mrtrimc(S, B, Xs) ->
- S2 = S - 1,
- X = binary:at(B, S2),
- case ordsets:is_element(X, Xs) of
- true -> do_mrtrimc(S2, B, Xs);
- false -> S
- end.
- %% @doc Reverse the bytes' order.
- reverse(Bin) when is_binary(Bin) ->
- S = bit_size(Bin),
- <<V:S/integer-little>> = Bin,
- <<V:S/integer-big>>.
- join([B | Bs], Sep) when is_binary(Sep) ->
- iolist_to_binary([B | add_separator(Bs, Sep)]);
- join([], _Sep) ->
- <<>>.
- add_separator([B | Bs], Sep) ->
- [Sep, B | add_separator(Bs, Sep)];
- add_separator([], _) ->
- [].
- %% @doc Repeat the binary `B' `C' times.
- duplicate(C, B) ->
- iolist_to_binary(lists:duplicate(C, B)).
- prefix(B, L) when is_binary(B), is_integer(L), L > 0 ->
- binary:part(B, 0, L).
- suffix(B, L) when is_binary(B), is_integer(L), L > 0 ->
- S = byte_size(B),
- binary:part(B, S - L, L).
- union(B1, B2) ->
- S = bit_size(B1),
- <<V1:S>> = B1,
- <<V2:S>> = B2,
- V3 = V1 bor V2,
- <<V3:S>>.
- subtract(B1, B2) ->
- S = bit_size(B1),
- <<V1:S>> = B1,
- <<V2:S>> = B2,
- V3 = (V1 bxor V2) band V1,
- <<V3:S>>.
- intersection(B1, B2) ->
- S = bit_size(B1),
- <<V1:S>> = B1,
- <<V2:S>> = B2,
- V3 = V1 band V2,
- <<V3:S>>.
- inverse(B1) ->
- S = bit_size(B1),
- <<V1:S>> = B1,
- V2 = bnot V1,
- <<V2:S>>.
- %% @doc string:to_integer/1 for binaries
- bin_to_int(Bin) ->
- bin_to_int(Bin, 0).
- bin_to_int(<<H, T/binary>>, X) when $0 =< H, H =< $9 ->
- bin_to_int(T, (X * 10) + (H - $0));
- bin_to_int(Bin, X) ->
- {X, Bin}.
- %% Remove longer patterns if shorter pattern matches
- %% Useful to run before binary:compile_pattern/1
- optimize_patterns(Patterns) ->
- Sorted = lists:usort(Patterns),
- remove_long_duplicates(Sorted).
- remove_long_duplicates([H | T]) ->
- %% match(Subject, Pattern)
- DedupT = [X || X <- T, binary:match(X, H) =:= nomatch],
- [H | remove_long_duplicates(DedupT)];
- remove_long_duplicates([]) ->
- [].
- join_path(PathList) ->
- join_path(PathList, <<>>).
- join_path([], Result) -> Result;
- join_path([<<>> | PathList], Result) -> join_path(PathList, Result);
- join_path([Path | PathList], Result) -> join_path(PathList, <<Result/binary, "/", Path/binary>>).
|