1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 1999-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: -module(bs_match_int_SUITE).
   20: 
   21: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   22: 	 init_per_group/2,end_per_group/2,
   23: 	 integer/1,signed_integer/1,dynamic/1,more_dynamic/1,mml/1,
   24: 	 match_huge_int/1,bignum/1,unaligned_32_bit/1]).
   25: 
   26: -include_lib("test_server/include/test_server.hrl").
   27: 
   28: -import(lists, [seq/2]).
   29: 
   30: suite() -> [{ct_hooks,[ts_install_cth]}].
   31: 
   32: all() -> 
   33:     [integer, signed_integer, dynamic, more_dynamic, mml,
   34:      match_huge_int, bignum, unaligned_32_bit].
   35: 
   36: groups() -> 
   37:     [].
   38: 
   39: init_per_suite(Config) ->
   40:     Config.
   41: 
   42: end_per_suite(_Config) ->
   43:     ok.
   44: 
   45: init_per_group(_GroupName, Config) ->
   46:     Config.
   47: 
   48: end_per_group(_GroupName, Config) ->
   49:     Config.
   50: 
   51: 
   52: integer(Config) when is_list(Config) ->
   53:     ?line 0 = get_int(mkbin([])),
   54:     ?line 0 = get_int(mkbin([0])),
   55:     ?line 42 = get_int(mkbin([42])),
   56:     ?line 255 = get_int(mkbin([255])),
   57:     ?line 256 = get_int(mkbin([1,0])),
   58:     ?line 257 = get_int(mkbin([1,1])),
   59:     ?line 258 = get_int(mkbin([1,2])),
   60:     ?line 258 = get_int(mkbin([1,2])),
   61:     ?line 65534 = get_int(mkbin([255,254])),
   62:     ?line 16776455 = get_int(mkbin([255,253,7])),
   63:     ?line 4245492555 = get_int(mkbin([253,13,19,75])),
   64:     ?line 4294967294 = get_int(mkbin([255,255,255,254])),
   65:     ?line 4294967295 = get_int(mkbin([255,255,255,255])),
   66:     ?line Eight = [200,1,19,128,222,42,97,111],
   67:     ?line cmp128(Eight, uint(Eight)),
   68:     ?line fun_clause(catch get_int(mkbin(seq(1,5)))),
   69:     ok.
   70: 
   71: get_int(Bin) ->
   72:     I = get_int1(Bin),
   73:     get_int(Bin, I).
   74: 
   75: get_int(Bin0, I) when size(Bin0) < 4 ->
   76:     Bin = <<0,Bin0/binary>>,
   77:     I = get_int1(Bin),
   78:     get_int(Bin, I);
   79: get_int(_, I) -> I.
   80: 
   81: get_int1(<<I:0>>) -> I;
   82: get_int1(<<I:8>>) -> I;
   83: get_int1(<<I:16>>) -> I;
   84: get_int1(<<I:24>>) -> I;
   85: get_int1(<<I:32>>) -> I.
   86: 
   87: cmp128(<<I:128>>, I) -> equal;
   88: cmp128(_, _) -> not_equal.
   89:     
   90: signed_integer(Config) when is_list(Config) ->
   91:     ?line {no_match,_} = sint(mkbin([])),
   92:     ?line {no_match,_} = sint(mkbin([1,2,3])),
   93:     ?line 127 = sint(mkbin([127])),
   94:     ?line -1 = sint(mkbin([255])),
   95:     ?line -128 = sint(mkbin([128])),
   96:     ?line 42 = sint(mkbin([42,255])),
   97:     ?line 127 = sint(mkbin([127,255])).
   98: 
   99: sint(Bin) ->
  100:     case Bin of
  101: 	<<I:8/signed>> -> I;
  102: 	<<I:8/signed,_:3,_:5>> -> I;
  103: 	Other -> {no_match,Other}
  104:     end.
  105: 
  106: uint(L) -> uint(L, 0).
  107: uint([H|T], Acc) -> uint(T, Acc bsl 8 bor H);
  108: uint([], Acc) -> Acc.
  109: 
  110: dynamic(Config) when is_list(Config) ->
  111:     dynamic(mkbin([255]), 8),
  112:     dynamic(mkbin([255,255]), 16),
  113:     dynamic(mkbin([255,255,255]), 24),
  114:     dynamic(mkbin([255,255,255,255]), 32),
  115:     ok.
  116: 
  117: dynamic(Bin, S1) when S1 >= 0 ->
  118:     S2 = size(Bin) * 8 - S1,
  119:     dynamic(Bin, S1, S2, (1 bsl S1) - 1, (1 bsl S2) - 1),
  120:     dynamic(Bin, S1-1);
  121: dynamic(_, _) -> ok.
  122: 
  123: dynamic(Bin, S1, S2, A, B) ->
  124: %    io:format("~p ~p ~p ~p\n", [S1,S2,A,B]),
  125:     case Bin of
  126: 	<<A:S1,B:S2>> ->
  127: 	    io:format("~p ~p ~p ~p\n", [S1,S2,A,B]),
  128: 	    ok;
  129: 	_Other -> erlang:error(badmatch, [Bin,S1,S2,A,B])
  130:     end.
  131: 
  132: more_dynamic(doc) -> "Extract integers at different alignments and of different sizes.";
  133: more_dynamic(Config) when is_list(Config) ->
  134: 
  135:     % Unsigned big-endian numbers.
  136:     Unsigned  = fun(Bin, List, SkipBef, N) ->
  137: 			SkipAft = 8*size(Bin) - N - SkipBef,
  138: 			<<_:SkipBef,Int:N,_:SkipAft>> = Bin,
  139: 			Int = make_int(List, N, 0)
  140: 		end,
  141:     ?line more_dynamic1(Unsigned, erlang:md5(mkbin([42]))),
  142: 
  143:     %% Signed big-endian numbers.
  144:     Signed  = fun(Bin, List, SkipBef, N) ->
  145: 		      SkipAft = 8*size(Bin) - N - SkipBef,
  146: 		      <<_:SkipBef,Int:N/signed,_:SkipAft>> = Bin,
  147: 		      case make_signed_int(List, N) of
  148: 			  Int -> ok;
  149: 			  Other ->
  150: 			      io:format("Bin = ~p,", [Bin]),
  151: 			      io:format("SkipBef = ~p, N = ~p", [SkipBef,N]),
  152: 			      io:format("Expected ~p, got ~p", [Int,Other]),
  153: 			      ?t:fail()
  154: 		      end
  155: 	      end,
  156:     ?line more_dynamic1(Signed, erlang:md5(mkbin([43]))),
  157: 
  158:     %% Unsigned little-endian numbers.
  159:     UnsLittle  = fun(Bin, List, SkipBef, N) ->
  160: 			 SkipAft = 8*size(Bin) - N - SkipBef,
  161: 			 <<_:SkipBef,Int:N/little,_:SkipAft>> = Bin,
  162: 			 Int = make_int(big_to_little(List, N), N, 0)
  163: 		 end,
  164:     ?line more_dynamic1(UnsLittle, erlang:md5(mkbin([44]))),
  165: 
  166:     %% Signed little-endian numbers.
  167:     SignLittle  = fun(Bin, List, SkipBef, N) ->
  168: 			  SkipAft = 8*size(Bin) - N - SkipBef,
  169: 			  <<_:SkipBef,Int:N/signed-little,_:SkipAft>> = Bin,
  170: 			  Little = big_to_little(List, N),
  171: 			  Int = make_signed_int(Little, N)
  172: 		  end,
  173:     ?line more_dynamic1(SignLittle, erlang:md5(mkbin([45]))),
  174: 
  175:     ok.
  176: 
  177: more_dynamic1(Action, Bin) ->
  178:     BitList = bits_to_list(binary_to_list(Bin), 16#80),
  179:     more_dynamic2(Action, Bin, BitList, 0).
  180: 
  181: more_dynamic2(Action, Bin, [_|T]=List, Bef) ->
  182:     more_dynamic3(Action, Bin, List, Bef, size(Bin)*8),
  183:     more_dynamic2(Action, Bin, T, Bef+1);
  184: more_dynamic2(_, _, [], _) -> ok.
  185: 
  186: more_dynamic3(Action, Bin, List, Bef, Aft) when Bef =< Aft ->
  187: %%    io:format("~p, ~p", [Bef,Aft-Bef]),
  188:     Action(Bin, List, Bef, Aft-Bef),
  189:     more_dynamic3(Action, Bin, List, Bef, Aft-1);
  190: more_dynamic3(_, _, _, _, _) -> ok.
  191: 
  192: big_to_little(List, N) -> big_to_little(List, N, []).
  193: 
  194: big_to_little([B0,B1,B2,B3,B4,B5,B6,B7|T], N, Acc) when N >= 8 ->
  195:     big_to_little(T, N-8, [B0,B1,B2,B3,B4,B5,B6,B7|Acc]);
  196: big_to_little(List, N, Acc) -> lists:sublist(List, 1, N) ++ Acc.
  197: 
  198: make_signed_int(_List, 0) -> 0;
  199: make_signed_int([0|_]=List, N) -> make_int(List, N, 0);
  200: make_signed_int([1|_]=List0, N) ->
  201:     List1 = reversed_sublist(List0, N, []),
  202:     List2 = two_complement_and_reverse(List1, 1, []),
  203:     -make_int(List2, length(List2), 0).
  204: 
  205: reversed_sublist(_List, 0, Acc) -> Acc;
  206: reversed_sublist([H|T], N, Acc) -> reversed_sublist(T, N-1, [H|Acc]).
  207:     
  208: two_complement_and_reverse([H|T], Carry, Acc) ->
  209:     Sum = 1-H+Carry,
  210:     two_complement_and_reverse(T, Sum div 2, [Sum rem 2|Acc]);
  211: two_complement_and_reverse([], Carry, Acc) -> [Carry|Acc].
  212: 
  213: make_int(_List, 0, Acc) -> Acc;
  214: make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H).
  215:     
  216: bits_to_list([_|T], 0) -> bits_to_list(T, 16#80);
  217: bits_to_list([H|_]=List, Mask) ->
  218:     [case H band Mask of
  219: 	 0 -> 0;
  220: 	 _ -> 1
  221:      end|bits_to_list(List, Mask bsr 1)];
  222: bits_to_list([], _) -> [].
  223: 
  224: fun_clause({'EXIT',{function_clause,_}}) -> ok.
  225: mkbin(L) when is_list(L) -> list_to_binary(L).
  226:     
  227: 
  228: mml(Config) when is_list(Config) ->
  229:     ?line single_byte_binary = mml_choose(<<42>>),
  230:     ?line multi_byte_binary = mml_choose(<<42,43>>).
  231: 
  232: mml_choose(<<_A:8>>) -> single_byte_binary;
  233: mml_choose(<<_A:8,_T/binary>>) -> multi_byte_binary.
  234: 
  235: match_huge_int(Config) when is_list(Config) ->
  236:     Sz = 1 bsl 27,
  237:     ?line Bin = <<0:Sz,13:8>>,
  238:     ?line skip_huge_int_1(Sz, Bin),
  239:     ?line 0 = match_huge_int_1(Sz, Bin),
  240: 
  241:     %% Test overflowing the size of an integer field.
  242:     ?line nomatch = overflow_huge_int_skip_32(Bin),
  243:     case erlang:system_info(wordsize) of
  244: 	4 ->
  245: 	    ?line nomatch = overflow_huge_int_32(Bin);
  246: 	8 ->
  247: 	    %% An attempt will be made to allocate heap space for
  248: 	    %% the bignum (which will probably fail); only if the
  249: 	    %% allocation succeds will the matching fail because
  250: 	    %% the binary is too small.
  251: 	    ok
  252:     end,
  253:     ?line nomatch = overflow_huge_int_skip_64(Bin),
  254:     ?line nomatch = overflow_huge_int_64(Bin),
  255: 
  256:     %% Test overflowing the size of an integer field using variables as sizes.
  257:     ?line Sizes = case erlang:system_info(wordsize) of
  258: 		      4 -> lists:seq(25, 32);
  259: 		      8 -> []
  260: 		  end ++ lists:seq(50, 64),
  261:     ?line ok = overflow_huge_int_unit128(Bin, Sizes),
  262: 
  263:     ok.
  264: 
  265: overflow_huge_int_unit128(Bin, [Sz0|Sizes]) ->
  266:     Sz = id(1 bsl Sz0),
  267:     case Bin of
  268: 	<<_:Sz/unit:128,0,_/binary>> ->
  269: 	    {error,Sz};
  270: 	_ ->
  271: 	    case Bin of
  272: 		<<Var:Sz/unit:128,0,_/binary>> ->
  273: 		    {error,Sz,Var};
  274: 		_ ->
  275: 		    overflow_huge_int_unit128(Bin, Sizes)
  276: 	    end
  277:     end;
  278: overflow_huge_int_unit128(_, []) -> ok.
  279: 
  280: match_huge_int_1(I, Bin) ->
  281:     <<Int:I,13>> = Bin,
  282:     Int.
  283: 
  284: skip_huge_int_1(I, Bin) ->
  285:     <<_:I,13>> = Bin.
  286: 
  287: overflow_huge_int_skip_32(<<_:4294967296,0,_/binary>>) -> 1; % 1 bsl 32
  288: overflow_huge_int_skip_32(<<_:33554432/unit:128,0,_/binary>>) -> 2; % 1 bsl 25
  289: overflow_huge_int_skip_32(<<_:67108864/unit:64,0,_/binary>>) -> 3; % 1 bsl 26
  290: overflow_huge_int_skip_32(<<_:134217728/unit:32,0,_/binary>>) -> 4; % 1 bsl 27
  291: overflow_huge_int_skip_32(<<_:268435456/unit:16,0,_/binary>>) -> 5; % 1 bsl 28
  292: overflow_huge_int_skip_32(<<_:536870912/unit:8,0,_/binary>>) -> 6; % 1 bsl 29
  293: overflow_huge_int_skip_32(<<_:1073741824/unit:8,0,_/binary>>) -> 7; % 1 bsl 30
  294: overflow_huge_int_skip_32(<<_:2147483648/unit:8,0,_/binary>>) -> 8; % 1 bsl 31
  295: overflow_huge_int_skip_32(_) -> nomatch.
  296: 
  297: overflow_huge_int_32(<<Int:4294967296,_/binary>>) -> {1,Int}; % 1 bsl 32
  298: overflow_huge_int_32(<<Int:33554432/unit:128,0,_/binary>>) -> {2,Int}; % 1 bsl 25
  299: overflow_huge_int_32(<<Int:67108864/unit:128,0,_/binary>>) -> {3,Int}; % 1 bsl 26
  300: overflow_huge_int_32(<<Int:134217728/unit:128,0,_/binary>>) -> {4,Int}; % 1 bsl 27
  301: overflow_huge_int_32(<<Int:268435456/unit:128,0,_/binary>>) -> {5,Int}; % 1 bsl 28
  302: overflow_huge_int_32(<<Int:536870912/unit:128,0,_/binary>>) -> {6,Int}; % 1 bsl 29
  303: overflow_huge_int_32(<<Int:1073741824/unit:128,0,_/binary>>) -> {7,Int}; % 1 bsl 30
  304: overflow_huge_int_32(<<Int:2147483648/unit:128,0,_/binary>>) -> {8,Int}; % 1 bsl 31
  305: overflow_huge_int_32(_) -> nomatch.
  306: 
  307: overflow_huge_int_skip_64(<<_:18446744073709551616,_/binary>>) -> 1; % 1 bsl 64
  308: overflow_huge_int_skip_64(<<_:144115188075855872/unit:128,0,_/binary>>) -> 2; % 1 bsl 57
  309: overflow_huge_int_skip_64(<<_:288230376151711744/unit:64,0,_/binary>>) -> 3; % 1 bsl 58
  310: overflow_huge_int_skip_64(<<_:576460752303423488/unit:32,0,_/binary>>) -> 4; % 1 bsl 59
  311: overflow_huge_int_skip_64(<<_:1152921504606846976/unit:16,0,_/binary>>) -> 5; % 1 bsl 60
  312: overflow_huge_int_skip_64(<<_:2305843009213693952/unit:8,0,_/binary>>) -> 6; % 1 bsl 61
  313: overflow_huge_int_skip_64(<<_:4611686018427387904/unit:8,0,_/binary>>) -> 7; % 1 bsl 62
  314: overflow_huge_int_skip_64(<<_:9223372036854775808/unit:8,0,_/binary>>) -> 8; % 1 bsl 63
  315: overflow_huge_int_skip_64(_) -> nomatch.
  316: 
  317: overflow_huge_int_64(<<Int:18446744073709551616,_/binary>>) -> {1,Int}; % 1 bsl 64
  318: overflow_huge_int_64(<<Int:144115188075855872/unit:128,0,_/binary>>) -> {2,Int}; % 1 bsl 57
  319: overflow_huge_int_64(<<Int:288230376151711744/unit:128,0,_/binary>>) -> {3,Int}; % 1 bsl 58
  320: overflow_huge_int_64(<<Int:576460752303423488/unit:128,0,_/binary>>) -> {4,Int}; % 1 bsl 59
  321: overflow_huge_int_64(<<Int:1152921504606846976/unit:128,0,_/binary>>) -> {5,Int}; % 1 bsl 60
  322: overflow_huge_int_64(<<Int:2305843009213693952/unit:128,0,_/binary>>) -> {6,Int}; % 1 bsl 61
  323: overflow_huge_int_64(<<Int:4611686018427387904/unit:128,0,_/binary>>) -> {7,Int}; % 1 bsl 62
  324: overflow_huge_int_64(<<Int:9223372036854775808/unit:128,0,_/binary>>) -> {8,Int}; % 1 bsl 63
  325: overflow_huge_int_64(_) -> nomatch.
  326: 
  327: bignum(Config) when is_list(Config) ->
  328:     ?line Bin = id(<<42,0:1024/unit:8,43>>),
  329:     ?line <<42:1025/little-integer-unit:8,_:8>> = Bin,
  330:     ?line <<_:8,43:1025/integer-unit:8>> = Bin,
  331: 
  332:     ?line BignumBin = id(<<0:512/unit:8,258254417031933722623:9/unit:8>>),
  333:     ?line <<258254417031933722623:(512+9)/unit:8>> = BignumBin,
  334:     erlang:garbage_collect(),			%Search for holes in debug-build.
  335:     ok.
  336: 
  337: unaligned_32_bit(Config) when is_list(Config) ->
  338:     %% There used to be a risk for heap overflow (fixed in R11B-5).
  339:     ?line L = unaligned_32_bit_1(<<-1:(64*1024)>>),
  340:     ?line unaligned_32_bit_verify(L, 1638).
  341: 
  342: unaligned_32_bit_1(<<1:1,U:32,_:7,T/binary>>) ->
  343:     [U|unaligned_32_bit_1(T)];
  344: unaligned_32_bit_1(_) ->
  345:     [].
  346: 
  347: unaligned_32_bit_verify([], 0) -> ok;
  348: unaligned_32_bit_verify([4294967295|T], N) when N > 0 ->
  349:     unaligned_32_bit_verify(T, N-1).
  350:     
  351: id(I) -> I.