1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2012-2017. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(asn1rtt_jer). 22%% encoding / decoding of BER 23-ifdef(DEBUG). 24-compile(export_all). 25-endif. 26%% For typeinfo JER 27-export([encode_jer/3, decode_jer/3]). 28 29 30%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 31%% Common code for all JER encoding/decoding 32%% 33%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34encode_jer(Module,InfoFunc,Val) -> 35 Info = Module:InfoFunc(), 36 encode_jer(Info,Val). 37 38%% {sequence, 39%% Name::atom() % The record name used for the sequence 40%% Arity::integer() % number of components 41%% CompInfos::[CompInfo()] % list of components with name, type etc 42%% Value::record matching name and arity 43 44encode_jer({sequence_tab,Simple,Sname,Arity,CompInfos},Value) 45 when tuple_size(Value) == Arity+1 -> 46 [Sname|Clist] = tuple_to_list(Value), 47 encode_jer_component_tab(CompInfos,Clist,Simple,#{}); 48%% {sequence, 49%% Name::atom() % The record name used for the sequence 50%% Arity::integer() % number of components 51%% CompInfos::[CompInfo()] % list of components with name, type etc 52%% Value::record matching name and arity 53encode_jer({sequence,Sname,Arity,CompInfos},Value) 54 when tuple_size(Value) == Arity+1 -> 55 [Sname|Clist] = tuple_to_list(Value), 56 encode_jer_component(CompInfos,Clist,[]); 57encode_jer(string,Str) when is_list(Str) -> 58 list_to_binary(Str); 59encode_jer({string,_Prop},Str) when is_list(Str) -> 60 list_to_binary(Str); 61encode_jer(string,Str) when is_binary(Str) -> 62 Str; 63encode_jer({string,_Prop},Str) when is_binary(Str) -> 64 Str; 65encode_jer('INTEGER',Int) when is_integer(Int) -> 66 Int; 67encode_jer({'INTEGER',{Min,Max}},Int) when is_integer(Int),Max >=Int, Int >= Min -> 68 Int; 69encode_jer({'INTEGER_NNL',_NNL},Int) when is_integer(Int) -> 70 Int; 71encode_jer(Type = {'INTEGER_NNL',NNList},Int) when is_atom(Int) -> 72 case lists:keyfind(Int, 1, NNList) of 73 {_, NewVal} -> 74 NewVal; 75 _ -> 76 exit({error, {asn1, {Type,Int}}}) 77 end; 78encode_jer({Type = {'INTEGER_NNL',_NNList},_Constraint},Int) when is_atom(Int) -> 79 encode_jer(Type,Int); 80encode_jer({{'INTEGER_NNL',_NNList},Constraint},Int) when is_integer(Int) -> 81 encode_jer({'INTEGER',Constraint},Int); 82encode_jer('BOOLEAN',Bool) when is_boolean(Bool) -> 83 Bool; 84encode_jer({'BOOLEAN',_Prop},Bool) when is_boolean(Bool) -> 85 Bool; 86encode_jer('NULL',_) -> 87 null; 88encode_jer(legacy_octet_string, Value) when is_list(Value) -> 89 bitstring2json(list_to_binary(Value)); 90encode_jer({legacy_octet_string,_Prop}, Value) when is_list(Value) -> 91 bitstring2json(list_to_binary(Value)); 92encode_jer(octet_string,Value) when is_binary(Value) -> 93 encode_jer({octet_string,[]}, Value); 94encode_jer({octet_string,_Prop}, Value) when is_binary(Value) -> 95 bitstring2json(Value); 96 97encode_jer({'ENUMERATED',EnumMap},Val) when is_map_key(Val,EnumMap) -> 98 Val; 99encode_jer({Type = {'ENUMERATED',_EnumList},_Constr}, Val) -> 100 encode_jer(Type,Val); 101 102encode_jer({'ENUMERATED_EXT',_EnumMap},Val) when is_atom(Val) -> 103 Val; 104encode_jer({Type = {'ENUMERATED_EXT',_EnumList},_Constr}, Val) -> 105 encode_jer(Type,Val); 106 107encode_jer({typeinfo,{Module,Func}},Val) -> 108 TypeInfo = Module:Func(), 109 encode_jer(TypeInfo,Val); 110 111encode_jer({sof,Type},Vals) when is_list(Vals) -> 112 [encode_jer(Type,Val)||Val <- Vals]; 113encode_jer({choice,Choices},{Alt,Value}) -> 114 case is_map_key(AltBin = atom_to_binary(Alt,utf8),Choices) of 115 true -> 116 EncodedVal = encode_jer(maps:get(AltBin,Choices),Value), 117 #{AltBin => EncodedVal}; 118 false -> 119 exit({error,{asn1,{invalid_choice,Alt,Choices}}}) 120 end; 121 122encode_jer(bit_string,Value) -> 123 Str = bitstring2json(Value), 124 #{value => Str, length => bit_size(Value)}; 125encode_jer({bit_string,FixedLength},Value) when is_bitstring(Value), is_integer(FixedLength) -> 126 Value2 = jer_padbitstr(Value,FixedLength), 127 bitstring2json(Value2); 128encode_jer(compact_bit_string,Compact) -> 129 BitStr = jer_compact2bitstr(Compact), 130 encode_jer(bit_string,BitStr); 131encode_jer({compact_bit_string,FixedLength},Compact = {_Unused,Binary}) when is_binary(Binary) -> 132 BitStr = jer_compact2bitstr(Compact), 133 encode_jer({bit_string,FixedLength},BitStr); 134encode_jer({bit_string_nnl,NNL},Value) -> 135 Value1 = jer_bit_str2bitstr(Value,NNL), 136 encode_jer(bit_string,Value1); 137encode_jer({{bit_string_nnl,NNL},FixedLength},Value) -> 138 Value1 = jer_bit_str2bitstr(Value,NNL), 139 encode_jer({bit_string,FixedLength},Value1); 140encode_jer({compact_bit_string_nnl,NNL},Value) -> 141 Value1 = jer_bit_str2bitstr(Value,NNL), 142 encode_jer(bit_string,Value1); 143encode_jer({{compact_bit_string_nnl,NNL},FixedLength},Value) -> 144 Value1 = jer_bit_str2bitstr(Value,NNL), 145 encode_jer({bit_string,FixedLength},Value1); 146%%encode_jer({legacy_bit_string_nnl,NNL},Value) -> 147%%encode_jer({{legacy_bit_string_nnl,NNL},FixedLength},Value) -> 148encode_jer('OBJECT IDENTIFIER',Oid) when is_tuple(Oid) -> 149 oid2json(Oid); 150encode_jer('RELATIVE-OID',Oid) when is_tuple(Oid) -> 151 oid2json(Oid); 152encode_jer({'ObjClassFieldType',_,_},Val) when is_binary(Val)-> 153 Val; 154encode_jer('ASN1_OPEN_TYPE',Val) when is_binary(Val) -> 155 Val; 156 157encode_jer(Type,Val) -> 158 exit({error,{asn1,{{encode,Type},Val}}}). 159 160 161encode_jer_component_tab([{_Name, _Type, 'OPTIONAL'} | CompInfos], [asn1_NOVALUE | Rest], Simple, MapAcc) -> 162 encode_jer_component_tab(CompInfos, Rest, Simple, MapAcc); 163encode_jer_component_tab([{_Name, _Type, {'DEFAULT',_}} | CompInfos], [asn1_DEFAULT | Rest], Simple, MapAcc) -> 164 encode_jer_component_tab(CompInfos, Rest, Simple, MapAcc); 165encode_jer_component_tab([{Name, Type, _OptOrDefault} | CompInfos], [Value | Rest], Simple, MapAcc) -> 166 Enc = encode_jer(Type, Value), 167 encode_jer_component_tab(CompInfos, Rest, Simple, MapAcc#{Name => Enc}); 168encode_jer_component_tab([], _, _Simple, MapAcc) -> 169 MapAcc. 170 171encode_jer_component([{_Name, _Type, 'OPTIONAL'} | CompInfos], [asn1_NOVALUE | Rest], Acc) -> 172 encode_jer_component(CompInfos, Rest, Acc); 173encode_jer_component([{_Name, _Type, {'DEFAULT',_}} | CompInfos], [asn1_DEFAULT | Rest], Acc) -> 174 encode_jer_component(CompInfos, Rest, Acc); 175encode_jer_component([{Name, Type, _OptOrDefault} | CompInfos], [Value | Rest], Acc) -> 176 Enc = encode_jer(Type, Value), 177 encode_jer_component(CompInfos, Rest, [{Name,Enc}|Acc]); 178encode_jer_component([], _, []) -> 179 #{}; % ensure that it is encoded as an empty object in JSON 180encode_jer_component([], _, Acc) -> 181 lists:reverse(Acc). 182 183decode_jer(Module,InfoFunc,Val) -> 184 Info = Module:InfoFunc(), 185 decode_jer(Info,Val). 186%% FIXME probably generate EnumList as a map with binaries as keys 187%% and check if the Value is in the map. Also take the extensionmarker into 188%% account and in that case allow any value but return as binary since it 189%% is a potential atom leak to convert unknown values to atoms 190%% maybe convert to existing atom 191%% FIXME this is a discrepancy compare with other backends which return {asn1_enum,Val} 192%% for unknown enum values when the type is extensible 193decode_jer({'ENUMERATED',_EnumList}, Val) when is_binary(Val) -> 194 binary_to_existing_atom(Val,utf8); 195decode_jer({'ENUMERATED',_EnumList}, Val) when is_boolean(Val) -> 196 Val; 197decode_jer({'ENUMERATED',_EnumList}, null) -> 198 null; 199decode_jer({Type = {'ENUMERATED',_EnumList},_Constr}, Val) -> 200 decode_jer(Type,Val); 201decode_jer({'ENUMERATED_EXT',EnumList}, Val) -> 202 decode_jer({'ENUMERATED',EnumList}, Val); 203decode_jer({Type = {'ENUMERATED_EXT',_EnumList},_Constr}, Val) -> 204 decode_jer(Type,Val); 205 206decode_jer({typeinfo,{Module,Func}},Val) -> 207 TypeInfo = Module:Func(), 208 decode_jer(TypeInfo,Val); 209decode_jer({sequence,Sname,_Arity,CompInfos},Value) 210 when is_map(Value) -> 211 DecodedComps = decode_jer_component(CompInfos,Value,[]), 212 list_to_tuple([Sname|DecodedComps]); 213 214%% Unfortunately we have to represent strings as lists to be compatible 215%% with the other backends. Should add an option to the compiler in the future 216%% which makes it possible to represent all strings as erlang binaries 217decode_jer(string,Str) when is_binary(Str) -> 218 binary_to_list(Str); 219decode_jer({string,_Prop},Str) when is_binary(Str) -> 220 binary_to_list(Str); 221decode_jer('INTEGER',Int) when is_integer(Int) -> 222 Int; 223decode_jer({'INTEGER',{Min,Max}},Int) when is_integer(Int),Max >=Int, Int >= Min -> 224 Int; 225decode_jer({Type = {'INTEGER_NNL',_NNList},_},Int) -> 226 decode_jer(Type,Int); 227decode_jer({'INTEGER_NNL',NNList},Int) -> 228 case lists:keyfind(Int, 2, NNList) of 229 {NewName, _} -> 230 NewName; 231 _ -> 232 Int 233 end; 234decode_jer('BOOLEAN',Bool) when is_boolean(Bool) -> 235 Bool; 236decode_jer({'BOOLEAN',_Prop},Bool) when is_boolean(Bool) -> 237 Bool; 238decode_jer('NULL',null) -> 239 'NULL'; 240decode_jer(legacy_octet_string,Str) when is_binary(Str) -> 241 json2octetstring2string(binary_to_list(Str)); 242decode_jer(octet_string,Str) when is_binary(Str) -> 243 json2octetstring2binary(binary_to_list(Str)); 244decode_jer({sof,Type},Vals) when is_list(Vals) -> 245 [decode_jer(Type,Val)||Val <- Vals]; 246decode_jer({choice,ChoiceTypes},ChoiceVal) -> 247 [{Alt,Val}] = maps:to_list(ChoiceVal), 248 case ChoiceTypes of 249 #{Alt := Type} -> 250 Type = maps:get(Alt,ChoiceTypes), 251 {binary_to_atom(Alt,utf8),decode_jer(Type,Val)}; 252 _ -> 253 exit({error,{asn1,{invalid_choice,Alt,maps:keys(ChoiceTypes)}}}) 254 end; 255decode_jer(bit_string,#{<<"value">> := Str, <<"length">> := Length}) -> 256 json2bitstring(binary_to_list(Str),Length); 257decode_jer({bit_string,FixedLength},Str) when is_binary(Str) -> 258 json2bitstring(binary_to_list(Str),FixedLength); 259decode_jer({bit_string_nnl,NNL},#{<<"value">> := Str, <<"length">> := Length}) -> 260 BitStr = json2bitstring(binary_to_list(Str),Length), 261 jer_bitstr2names(BitStr,NNL); 262decode_jer({{bit_string_nnl,NNL},FixedLength},Str) when is_binary(Str)-> 263 BitStr = json2bitstring(binary_to_list(Str),FixedLength), 264 jer_bitstr2names(BitStr,NNL); 265decode_jer({compact_bit_string_nnl,NNL},Value) -> 266 decode_jer({bit_string_nnl,NNL},Value); 267decode_jer({{compact_bit_string_nnl,NNL},FixedLength},Value) -> 268 decode_jer({{bit_string_nnl,NNL},FixedLength},Value); 269decode_jer(compact_bit_string,#{<<"value">> := Str, <<"length">> := Length}) -> 270 BitStr = json2bitstring(binary_to_list(Str),Length), 271 jer_bitstr2compact(BitStr); 272decode_jer({compact_bit_string,FixedLength},Str) -> 273 BitStr = json2bitstring(binary_to_list(Str),FixedLength), 274 Unused = (8 - (FixedLength rem 8)) band 7, 275 {Unused,<<BitStr/bitstring,0:Unused>>}; 276decode_jer('OBJECT IDENTIFIER',OidBin) when is_binary(OidBin) -> 277 json2oid(OidBin); 278decode_jer('RELATIVE-OID',OidBin) when is_binary(OidBin) -> 279 json2oid(OidBin); 280decode_jer({'ObjClassFieldType',_,_},Bin) when is_binary(Bin) -> 281 Bin; 282decode_jer('ASN1_OPEN_TYPE',Bin) when is_binary(Bin) -> 283 Bin; 284decode_jer(Type,Val) -> 285 exit({error,{asn1,{{decode,Type},Val}}}). 286 287decode_jer_component([{Name, Type, _OptOrDefault} | CompInfos], VMap, Acc) 288 when is_map_key(Name, VMap) -> 289 Value = maps:get(Name, VMap), 290 Dec = decode_jer(Type, Value), 291 decode_jer_component(CompInfos, VMap, [Dec | Acc]); 292decode_jer_component([{_Name, _Type, 'OPTIONAL'} | CompInfos], VMap, Acc) -> 293 decode_jer_component(CompInfos, VMap, [asn1_NOVALUE | Acc]); 294decode_jer_component([{_Name, _Type, {'DEFAULT',Dvalue}} | CompInfos], VMap, Acc) -> 295 decode_jer_component(CompInfos, VMap, [Dvalue | Acc]); 296decode_jer_component([{Name, _Type, _OptOrDefault} | _CompInfos], VMap, _Acc) -> 297 exit({error,{asn1,{{decode,{mandatory_component_missing,Name}},VMap}}}); 298decode_jer_component([], _, Acc) -> 299 lists:reverse(Acc). 300 301%% This is the default representation of octet string i.e binary 302json2octetstring2binary(Value) -> 303 list_to_binary(json2octetstring(Value,[])). 304 305%% This is the legacy_types representation of octet string i.e as a list 306json2octetstring2string(Value) -> 307 json2octetstring(Value,[]). 308 309json2octetstring([A1,A2|Rest],Acc) -> 310 Int = list_to_integer([A1,A2],16), 311 json2octetstring(Rest,[Int|Acc]); 312json2octetstring([], Acc) -> 313 lists:reverse(Acc). 314 315json2bitstring(Value,Length) -> 316 json2bitstring(Value,Length,[]). 317 318json2bitstring([A1,A2],Length,Acc) -> 319 Int = list_to_integer([A1,A2],16) bsr (8-Length), 320 Bin = list_to_binary(lists:reverse(Acc)), 321 << Bin/binary,Int:Length>>; 322json2bitstring([A1,A2|Rest],Length,Acc) -> 323 Int = list_to_integer([A1,A2],16), 324 json2bitstring(Rest,Length-8,[Int|Acc]); 325json2bitstring([],0,Acc) -> 326 Bin = list_to_binary(lists:reverse(Acc)), 327 Bin. 328 329bitstring2json(BitStr) when is_binary(BitStr) -> 330 octetstring2json(binary_to_list(BitStr)); 331bitstring2json(BitStr) -> 332 Pad = 8 - bit_size(BitStr) rem 8, 333 NewStr = <<BitStr/bitstring,0:Pad>>, 334 octetstring2json(binary_to_list(NewStr)). 335 336octetstring2json(List) when is_list(List) -> 337 list_to_binary([begin Num = integer_to_list(X,16), 338 if length(Num) == 1 -> "0"++Num; 339 true -> Num 340 end 341 end|| X<-List]). 342 343oid2json(Oid) when is_tuple(Oid) -> 344 OidList = tuple_to_list(Oid), 345 OidNumberStr = [integer_to_list(V)|| V <- OidList], 346 oid2json(OidNumberStr,[]). 347 348oid2json([Num|T],[]) -> 349 oid2json(T,[Num]); 350oid2json([Num|T],Acc) -> 351 oid2json(T,[Num,$.|Acc]); 352oid2json([],Acc) -> 353 list_to_binary(lists:reverse(Acc)). 354 355json2oid(OidStr) when is_binary(OidStr) -> 356 OidList = binary:split(OidStr,[<<".">>],[global]), 357 OidNumList = [binary_to_integer(Num)||Num <- OidList], 358 list_to_tuple(OidNumList). 359 360jer_bit_str2bitstr(Compact = {_Unused,_Binary}, _NamedBitList) -> 361 jer_compact2bitstr(Compact); 362jer_bit_str2bitstr(Int, _NamedBitList) when is_integer(Int) -> 363 jer_compact2bitstr(Int); 364jer_bit_str2bitstr(BitList = [Bit|_], _NamedBitList) when Bit == 1; Bit == 0 -> 365 Int = list_to_integer([case B of 0 -> $0; 1 -> $1 end || B <- BitList],2), 366 Len = length(BitList), 367 <<Int:Len>>; 368jer_bit_str2bitstr([H | _] = Bits, NamedBitList) 369 when is_atom(H) -> 370 jer_do_encode_named_bit_string(Bits, NamedBitList); 371jer_bit_str2bitstr([{bit, _} | _] = Bits, NamedBitList) -> 372 jer_do_encode_named_bit_string(Bits, NamedBitList); 373jer_bit_str2bitstr([], _NamedBitList) -> 374 <<>>; 375jer_bit_str2bitstr(BitStr,_NamedBitList) when is_bitstring(BitStr) -> 376 BitStr. 377 378jer_compact2bitstr({Unused,Binary}) -> 379 Size = bit_size(Binary) - Unused, 380 <<BitStr:Size/bitstring,_/bitstring >> = Binary, 381 BitStr; 382jer_compact2bitstr(Int) when is_integer(Int) -> 383 jer_int2bitstr(Int); 384jer_compact2bitstr(BitList = [Bit|_]) when Bit == 1; Bit == 0 -> 385 IntStr = jer_skip_trailing_zeroes(BitList,[]), 386 Int = list_to_integer(IntStr,2), 387 Len = length(IntStr), 388 <<Int:Len>>. 389 390jer_skip_trailing_zeroes([1|Rest],Acc) -> 391 jer_skip_trailing_zeroes(Rest,[$1|Acc]); 392jer_skip_trailing_zeroes([0|Rest],Acc) -> 393 jer_skip_trailing_zeroes(Rest,[$0|Acc]); 394jer_skip_trailing_zeroes([],[$0|Acc]) -> 395 jer_skip_trailing_zeroes([],Acc); 396jer_skip_trailing_zeroes([],Acc) -> 397 lists:reverse(Acc). 398 399 400 401 402jer_padbitstr(BitStr,FixedLength) when bit_size(BitStr) == FixedLength -> 403 BitStr; 404jer_padbitstr(BitStr,FixedLength) when bit_size(BitStr) < FixedLength -> 405 Len = bit_size(BitStr), 406 PadLen = FixedLength - Len, 407 <<BitStr/bitstring,0:PadLen>>. 408 409jer_int2bitstr(Int) when is_integer(Int), Int >= 0 -> 410 jer_int2bitstr(Int,<<>>). 411 412jer_int2bitstr(0,Acc) -> 413 Acc; 414jer_int2bitstr(Int,Acc) -> 415 Bit = Int band 1, 416 jer_int2bitstr(Int bsr 1,<<Acc/bitstring,Bit:1>>). 417 418jer_bitstr2compact(BitStr) -> 419 Size = bit_size(BitStr), 420 Unused = (8 - Size rem 8) band 7, 421 {Unused,<<BitStr/bitstring,0:Unused>>}. 422 423jer_do_encode_named_bit_string([FirstVal | RestVal], NamedBitList) -> 424 ToSetPos = jer_get_all_bitposes([FirstVal | RestVal], NamedBitList, []), 425 Size = lists:max(ToSetPos) + 1, 426 BitList = jer_make_and_set_list(Size, ToSetPos, 0), 427 encode_bitstring(BitList). 428 429jer_get_all_bitposes([{bit, ValPos} | Rest], NamedBitList, Ack) -> 430 jer_get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]); 431jer_get_all_bitposes([Val | Rest], NamedBitList, Ack) when is_atom(Val) -> 432 case lists:keyfind(Val, 1, NamedBitList) of 433 {_ValName, ValPos} -> 434 jer_get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]); 435 _ -> 436 exit({error, {asn1, {bitstring_namedbit, Val}}}) 437 end; 438jer_get_all_bitposes([], _NamedBitList, Ack) -> 439 lists:sort(Ack). 440 441jer_make_and_set_list(0, [], _) -> 442 []; 443jer_make_and_set_list(0, _, _) -> 444 exit({error, {asn1, bitstring_sizeconstraint}}); 445jer_make_and_set_list(Len, [XPos | SetPos], XPos) -> 446 [1 | jer_make_and_set_list(Len - 1, SetPos, XPos + 1)]; 447jer_make_and_set_list(Len, [Pos | SetPos], XPos) -> 448 [0 | jer_make_and_set_list(Len - 1, [Pos | SetPos], XPos + 1)]; 449jer_make_and_set_list(Len, [], XPos) -> 450 [0 | jer_make_and_set_list(Len - 1, [], XPos + 1)]. 451 452%%================================================================= 453%% Do the actual encoding 454%% ([bitlist]) -> {ListLen, UnusedBits, OctetList} 455%%================================================================= 456 457encode_bitstring([B8, B7, B6, B5, B4, B3, B2, B1 | Rest]) -> 458 Val = (B8 bsl 7) bor (B7 bsl 6) bor (B6 bsl 5) bor (B5 bsl 4) bor 459 (B4 bsl 3) bor (B3 bsl 2) bor (B2 bsl 1) bor B1, 460 encode_bitstring(Rest, <<Val>>); 461encode_bitstring(Val) -> 462 unused_bitlist(Val, <<>>). 463 464encode_bitstring([B8, B7, B6, B5, B4, B3, B2, B1 | Rest], Ack) -> 465 Val = (B8 bsl 7) bor (B7 bsl 6) bor (B6 bsl 5) bor (B5 bsl 4) bor 466 (B4 bsl 3) bor (B3 bsl 2) bor (B2 bsl 1) bor B1, 467 encode_bitstring(Rest, [Ack | [Val]]); 468%%even multiple of 8 bits.. 469encode_bitstring([], Ack) -> 470 Ack; 471%% unused bits in last octet 472encode_bitstring(Rest, Ack) -> 473 unused_bitlist(Rest,Ack). 474 475%%%%%%%%%%%%%%%%%% 476%% unused_bitlist([list of ones and zeros <= 7], 7, []) -> 477%% {Unused bits, Last octet with bits moved to right} 478unused_bitlist([], Ack) -> 479 Ack; 480unused_bitlist([Bit | Rest], Ack) -> 481 unused_bitlist(Rest, <<Ack/bitstring,Bit:1>>). 482 483jer_bitstr2names(BitStr,[]) -> 484 BitStr; 485jer_bitstr2names(BitStr,NNL) -> 486 %% Fixme, the sorting should be done in compile time, maybe it already is 487 SortedList = lists:keysort(2,NNL), %% Should be from bit 0 to bit N 488 jer_bitstr2names(BitStr,SortedList,0,[]). 489 490jer_bitstr2names(<<1:1,BitStr/bitstring>>,[{Name,Pos}|Rest],Pos,Acc) -> 491 jer_bitstr2names(BitStr,Rest,Pos+1,[Name|Acc]); 492jer_bitstr2names(<<1:1,BitStr/bitstring>>,NNL,Num,Acc) -> 493 jer_bitstr2names(BitStr,NNL,Num+1,[{bit,Num}|Acc]); 494jer_bitstr2names(<<0:1,BitStr/bitstring>>,[{_,Num}|Rest],Num,Acc) -> 495 jer_bitstr2names(BitStr,Rest,Num+1,Acc); 496jer_bitstr2names(<<0:1,BitStr/bitstring>>,NNL,Num,Acc) -> 497 jer_bitstr2names(BitStr,NNL,Num+1,Acc); 498jer_bitstr2names(<<>>,_,_,Acc) -> 499 lists:reverse(Acc). 500 501 502 503 504 505 506