1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 2000-2011. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: 
   21: -module(bs_match_bin_SUITE).
   22: 
   23: -author('bjorn@erix.ericsson.se').
   24: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
   25: 	 init_per_testcase/2,end_per_testcase/2,
   26: 	 init_per_suite/1,end_per_suite/1,
   27: 	 byte_split_binary/1,bit_split_binary/1,match_huge_bin/1]).
   28: 
   29: -include_lib("test_server/include/test_server.hrl").
   30: 
   31: suite() -> [{ct_hooks,[ts_install_cth]}].
   32: 
   33: all() -> 
   34:     [byte_split_binary, bit_split_binary, match_huge_bin].
   35: 
   36: groups() -> 
   37:     [].
   38: 
   39: init_per_group(_GroupName, Config) ->
   40:     Config.
   41: 
   42: end_per_group(_GroupName, Config) ->
   43:     Config.
   44: 
   45: init_per_testcase(_Case, Config) ->
   46:     test_lib:interpret(?MODULE),
   47:     Dog = test_server:timetrap(?t:minutes(1)),
   48:     [{watchdog,Dog}|Config].
   49: 
   50: end_per_testcase(_Case, Config) ->
   51:     Dog = ?config(watchdog, Config),
   52:     ?t:timetrap_cancel(Dog),
   53:     ok.
   54: 
   55: init_per_suite(Config) when is_list(Config) ->
   56:     ?line test_lib:interpret(?MODULE),
   57:     ?line true = lists:member(?MODULE, int:interpreted()),
   58:     Config.
   59: 
   60: end_per_suite(Config) when is_list(Config) ->
   61:     ok.
   62: 
   63: byte_split_binary(doc) -> "Tries to split a binary at all byte-aligned positions.";
   64: byte_split_binary(Config) when is_list(Config) ->
   65:     ?line L = lists:seq(0, 57),
   66:     ?line B = mkbin(L),
   67:     ?line byte_split(L, B, size(B)),
   68:     ?line Unaligned = make_unaligned_sub_binary(B),
   69:     ?line byte_split(L, Unaligned, size(Unaligned)).
   70: 
   71: byte_split(L, B, Pos) when Pos >= 0 ->
   72:     ?line Sz1 = Pos,
   73:     ?line Sz2 = size(B) - Pos,
   74:     ?line <<B1:Sz1/binary,B2:Sz2/binary>> = B,
   75:     ?line B1 = list_to_binary(lists:sublist(L, 1, Pos)),
   76:     ?line B2 = list_to_binary(lists:nthtail(Pos, L)),
   77:     ?line byte_split(L, B, Pos-1);
   78: byte_split(_, _, _) -> ok.
   79: 
   80: bit_split_binary(doc) -> "Tries to split a binary at all positions.";
   81: bit_split_binary(Config) when is_list(Config) ->
   82:     Fun = fun(Bin, List, SkipBef, N) ->
   83: 		  ?line SkipAft = 8*size(Bin) - N - SkipBef,
   84: 		  %%io:format("~p, ~p, ~p", [SkipBef,N,SkipAft]),
   85: 		  ?line <<_:SkipBef,OutBin:N/binary-unit:1,_:SkipAft>> = Bin,
   86: 		  ?line OutBin = make_bin_from_list(List, N)
   87: 	  end,
   88:     ?line bit_split_binary1(Fun, erlang:md5(<<1,2,3>>)),
   89:     ?line bit_split_binary1(Fun,
   90: 			    make_unaligned_sub_binary(erlang:md5(<<1,2,3>>))),
   91:     ok.
   92: 
   93: bit_split_binary1(Action, Bin) ->
   94:     BitList = bits_to_list(binary_to_list(Bin), 16#80),
   95:     bit_split_binary2(Action, Bin, BitList, 0).
   96: 
   97: bit_split_binary2(Action, Bin, [_|T]=List, Bef) ->
   98:     bit_split_binary3(Action, Bin, List, Bef, size(Bin)*8),
   99:     bit_split_binary2(Action, Bin, T, Bef+1);
  100: bit_split_binary2(_, _, [], _) -> ok.
  101: 
  102: bit_split_binary3(Action, Bin, List, Bef, Aft) when Bef =< Aft ->
  103:     Action(Bin, List, Bef, (Aft-Bef) div 8 * 8),
  104:     bit_split_binary3(Action, Bin, List, Bef, Aft-8);
  105: bit_split_binary3(_, _, _, _, _) -> ok.
  106: 
  107: make_bin_from_list(_, 0) -> mkbin([]);
  108: make_bin_from_list(List, N) ->
  109:     list_to_binary([make_int(List, 8, 0),
  110: 		    make_bin_from_list(lists:nthtail(8, List), N-8)]).
  111: 
  112: 
  113: make_int(_, 0, Acc) -> Acc;
  114: make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H).
  115: 
  116: bits_to_list([_|T], 0) -> bits_to_list(T, 16#80);
  117: bits_to_list([H|_]=List, Mask) ->
  118:     [case H band Mask of
  119: 	 0 -> 0;
  120: 	 _ -> 1
  121:      end|bits_to_list(List, Mask bsr 1)];
  122: bits_to_list([], _) -> [].
  123: 
  124: mkbin(L) when is_list(L) -> list_to_binary(L).
  125: 
  126: make_unaligned_sub_binary(Bin0) ->
  127:     Bin1 = <<0:3,Bin0/binary,31:5>>,
  128:     Sz = size(Bin0),
  129:     <<0:3,Bin:Sz/binary,31:5>> = id(Bin1),
  130:     Bin.
  131: 
  132: id(I) -> I.
  133: 
  134: match_huge_bin(Config) when is_list(Config) ->
  135:     ?line Bin = <<0:(1 bsl 27),13:8>>,
  136:     ?line skip_huge_bin_1(1 bsl 27, Bin),
  137:     ?line 16777216 = match_huge_bin_1(1 bsl 27, Bin),
  138: 
  139:     %% Test overflowing the size of a binary field.
  140:     ?line nomatch = overflow_huge_bin_skip_32(Bin),
  141:     ?line nomatch = overflow_huge_bin_32(Bin),
  142:     ?line nomatch = overflow_huge_bin_skip_64(Bin),
  143:     ?line nomatch = overflow_huge_bin_64(Bin),
  144: 
  145:     %% Size in variable
  146:     ?line ok = overflow_huge_bin(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
  147:     ?line ok = overflow_huge_bin_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
  148: 
  149:     ok.
  150: 
  151: overflow_huge_bin(Bin, [Sz0|Sizes]) ->
  152:     Sz = id(1 bsl Sz0),
  153:     case Bin of
  154: 	<<_:Sz/binary-unit:8,0,_/binary>> ->
  155: 	    {error,Sz};
  156: 	_ ->
  157: 	    case Bin of
  158: 		<<NewBin:Sz/binary-unit:8,0,_/binary>> ->
  159: 		    {error,Sz,size(NewBin)};
  160: 		_ ->
  161: 		    overflow_huge_bin(Bin, Sizes)
  162: 	    end
  163:     end;
  164: overflow_huge_bin(_, []) -> ok.
  165: 
  166: overflow_huge_bin_unit128(Bin, [Sz0|Sizes]) ->
  167:     Sz = id(1 bsl Sz0),
  168:     case Bin of
  169: 	<<_:Sz/binary-unit:128,0,_/binary>> ->
  170: 	    {error,Sz};
  171: 	_ ->
  172: 	    case Bin of
  173: 		<<NewBin:Sz/binary-unit:128,0,_/binary>> ->
  174: 		    {error,Sz,size(NewBin)};
  175: 		_ ->
  176: 		    overflow_huge_bin_unit128(Bin, Sizes)
  177: 	    end
  178:     end;
  179: overflow_huge_bin_unit128(_, []) -> ok.
  180: 
  181: skip_huge_bin_1(I, Bin) ->
  182:     <<_:I/binary-unit:1,13>> = Bin,
  183:     ok.
  184: 
  185: match_huge_bin_1(I, Bin) ->
  186:     case Bin of
  187: 	<<Val:I/binary-unit:1,13>> -> size(Val);
  188: 	_ -> nomatch
  189:     end.
  190: 
  191: overflow_huge_bin_skip_32(<<_:4294967296/binary,0,_/binary>>) -> 1; % 1 bsl 32
  192: overflow_huge_bin_skip_32(<<_:33554432/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 25
  193: overflow_huge_bin_skip_32(<<_:67108864/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 26
  194: overflow_huge_bin_skip_32(<<_:134217728/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 27
  195: overflow_huge_bin_skip_32(<<_:268435456/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 28
  196: overflow_huge_bin_skip_32(<<_:536870912/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 29
  197: overflow_huge_bin_skip_32(<<_:1073741824/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 30
  198: overflow_huge_bin_skip_32(<<_:2147483648/binary-unit:8,0,_/binary>>) -> 8; % 1 bsl 31
  199: overflow_huge_bin_skip_32(_) -> nomatch.
  200: 
  201: overflow_huge_bin_32(<<Bin:4294967296/binary,_/binary>>) -> {1,Bin}; % 1 bsl 32
  202: overflow_huge_bin_32(<<Bin:33554432/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 25
  203: overflow_huge_bin_32(<<Bin:67108864/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 26
  204: overflow_huge_bin_32(<<Bin:134217728/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 27
  205: overflow_huge_bin_32(<<Bin:268435456/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 28
  206: overflow_huge_bin_32(<<Bin:536870912/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 29
  207: overflow_huge_bin_32(<<Bin:1073741824/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 30
  208: overflow_huge_bin_32(<<Bin:2147483648/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 31
  209: overflow_huge_bin_32(_) -> nomatch.
  210: 
  211: overflow_huge_bin_skip_64(<<_:18446744073709551616/binary,0,_/binary>>) -> 1; % 1 bsl 64
  212: overflow_huge_bin_skip_64(<<_:144115188075855872/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 57
  213: overflow_huge_bin_skip_64(<<_:288230376151711744/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 58
  214: overflow_huge_bin_skip_64(<<_:576460752303423488/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 59
  215: overflow_huge_bin_skip_64(<<_:1152921504606846976/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 60
  216: overflow_huge_bin_skip_64(<<_:2305843009213693952/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 61
  217: overflow_huge_bin_skip_64(<<_:4611686018427387904/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 62
  218: overflow_huge_bin_skip_64(<<_:9223372036854775808/binary-unit:8,_/binary>>) -> 8; % 1 bsl 63
  219: overflow_huge_bin_skip_64(_) -> nomatch.
  220: 
  221: overflow_huge_bin_64(<<Bin:18446744073709551616/binary,_/binary>>) -> {1,Bin}; % 1 bsl 64
  222: overflow_huge_bin_64(<<Bin:144115188075855872/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 57
  223: overflow_huge_bin_64(<<Bin:288230376151711744/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 58
  224: overflow_huge_bin_64(<<Bin:576460752303423488/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 59
  225: overflow_huge_bin_64(<<Bin:1152921504606846976/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 60
  226: overflow_huge_bin_64(<<Bin:2305843009213693952/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 61
  227: overflow_huge_bin_64(<<Bin:4611686018427387904/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 62
  228: overflow_huge_bin_64(<<Bin:9223372036854775808/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 63
  229: overflow_huge_bin_64(_) -> nomatch.