diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/megaco/src/text/megaco_text_mini_parser.hrl | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/megaco/src/text/megaco_text_mini_parser.hrl')
-rw-r--r-- | lib/megaco/src/text/megaco_text_mini_parser.hrl | 1246 |
1 files changed, 1246 insertions, 0 deletions
diff --git a/lib/megaco/src/text/megaco_text_mini_parser.hrl b/lib/megaco/src/text/megaco_text_mini_parser.hrl new file mode 100644 index 0000000000..bb6ee43247 --- /dev/null +++ b/lib/megaco/src/text/megaco_text_mini_parser.hrl @@ -0,0 +1,1246 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose : Define semantic text parser actions +%%---------------------------------------------------------------------- + + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/include/megaco_message_v2.hrl"). +-include("megaco_text_tokens.hrl"). + +-define(d(F,A), io:format("DBG:"++F++"~n",A)). + +make_safe_token({_TokenTag, Line, Text}) -> + {safeToken, Line, Text}. + +% ensure_value({safeToken, _Line, Text}) -> +% ensure_value(Text); +% ensure_value({'QuotedChars', _Line, Text}) -> +% ensure_value(Text); +% ensure_value(Text) when list(Text) -> +% Text. %% BUGBUG: ensure length + +% %% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +% ensure_NAME({_TokenTag, _Line, Text}) -> +% Text. %% BUGBUG: ensure length and chars + +% ensure_requestID({safeToken, _Line, "*"}) -> +% ?megaco_all_request_id; +% ensure_requestID(RequestId) -> +% ensure_uint32(RequestId). + +% ensure_streamID(StreamId) -> +% ensure_uint16(StreamId). + +ensure_auth_header(SpiToken, SnToken, AdToken) -> + Spi = ensure_hex(SpiToken, 8, 8), + Sn = ensure_hex(SnToken, 8, 8), + Ad = ensure_hex(AdToken, 24, 64), + #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}. + +%% ContextID = (UINT32 / "*" / "-" / "$") +% ensure_contextID({_TokenTag, _Line, Text}) -> +% case Text of +% "*" -> ?megaco_all_context_id; +% "-" -> ?megaco_null_context_id; +% "\$" -> ?megaco_choose_context_id; +% Int -> ensure_uint32(Int) +% end. + +ensure_domainAddress([{_T, _L, _A} = Addr0], Port) -> + Addr = ensure_ip4addr(Addr0), + {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress([colon,colon], Port) -> + Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}; +ensure_domainAddress(Addr0, Port) -> + Addr = ensure_ip6addr(Addr0), + {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}. + + +ensure_ip4addr({TokenTag, Line, Addr}) -> + case string:tokens(Addr, [$.]) of + [T1, T2, T3, T4] -> + A1 = ensure_uint({TokenTag, Line, T1}, 0, 255), + A2 = ensure_uint({TokenTag, Line, T2}, 0, 255), + A3 = ensure_uint({TokenTag, Line, T3}, 0, 255), + A4 = ensure_uint({TokenTag, Line, T4}, 0, 255), + [A1, A2, A3, A4]; + _ -> + return_error(Line, {bad_IP4address, Addr}) + end. + + +ensure_ip6addr([colon,colon|T]) -> + [H1|T1] = lists:reverse(T), + case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + lists:duplicate(16 - length(B), 0) ++ B; + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; +ensure_ip6addr(L) -> + case lists:reverse(L) of + [colon, colon| T] -> + case do_ensure_ip6addr(T, true, [], 1) of + {true, A} when length(A) == 16 -> + A; + {true, B} when length(B) < 16 -> + B ++ lists:duplicate(16 - length(B), 0); + {true, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}}) + end; + [H|L1] -> % A (last element) could be an ip4 address + case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of + {false, A} when length(A) == 16 -> + A; + %% allow a pad even if the address is full (i.e. 16) + {true, B} when length(B) =< 17 -> + do_ensure_ip6addr_padding(B, 0); + {Pad, C} -> + throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}}) + end + + end. + + +do_ensure_ip6addr([], Pad, Acc, _) -> + {Pad, lists:flatten(Acc)}; +do_ensure_ip6addr([colon,colon|T], false, Acc, Line) -> + do_ensure_ip6addr(T, true, [pad|Acc], Line); +do_ensure_ip6addr([colon,colon|T], true, Acc, Line) -> + return_error(Line, {bad_mid_duplicate_padding, T, Acc}); +do_ensure_ip6addr([colon|T], Pad, Acc, Line) -> + do_ensure_ip6addr(T, Pad, Acc, Line); +do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) -> + do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line). + +do_ensure_ip6addr_padding([], _) -> + []; +do_ensure_ip6addr_padding([pad|T], N) -> + lists:duplicate(16 - (N + length(T)), 0) ++ T; +do_ensure_ip6addr_padding([H|T], N) -> + [H|do_ensure_ip6addr_padding(T, N+1)]. + +ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) -> + case string:tokens(Addr, [$.]) of + [T1, T2, T3, T4] -> + A1 = ensure_uint({TokenTag, Line, T1}, 0, 255), + A2 = ensure_uint({TokenTag, Line, T2}, 0, 255), + A3 = ensure_uint({TokenTag, Line, T3}, 0, 255), + A4 = ensure_uint({TokenTag, Line, T4}, 0, 255), + [A1, A2, A3, A4]; + _ -> + ensure_hex4(V) + %% %% BMK BMK BMK + %% %% Here we should test for hexseq + %% return_error(Line, {bad_IP4address, Addr}) + end. + +ensure_hex4({_TokenTag, Line, Hex4}) + when (length(Hex4) =< 4) andalso (length(Hex4) > 0) -> + case (catch do_ensure_hex4(Hex4)) of + IL when is_list(IL) andalso (length(IL) =:= 2) -> + IL; + Error -> + return_error(Line, {bad_hex4, Hex4, Error}) + end. + +do_ensure_hex4([_H1, _H2, _H3, _H4] = H) -> + hex_to_int(H, []); +do_ensure_hex4([H2, H3, H4]) -> + hex_to_int([$0, H2, H3, H4], []); +do_ensure_hex4([H3, H4]) -> + hex_to_int([$0, $0, H3, H4], []); +do_ensure_hex4([H4]) -> + hex_to_int([$0, $0, $0, H4], []). + +ensure_domainName({_TokenTag, _Line, Name}, Port) -> + %% BUGBUG: validate name + {domainName, #'DomainName'{name = Name, portNumber = Port}}. + +%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT) +% ensure_extensionParameter({_TokenTag, Line, Text}) -> +% case Text of +% [X, S | _Chars] -> +% if +% X /= $X, X /= $x, +% S /= $+, S /= $- -> +% return_error(Line, {bad_extension_parameter, Text}); +% true -> +% {extension_parameter, Text} +% end; +% _ -> +% return_error(Line, {bad_extension_parameter, Text}) +% end. + +ensure_message(MegacopToken, MID) -> + #'ServiceChangeProfile'{profileName = Name, + version = Version} = + ensure_profile(MegacopToken), + case Name of + "megaco" -> + #'Message'{version = Version, mId = MID}; + [$!] -> + #'Message'{version = Version, mId = MID} + end. + + +%% modemType = (V32bisToken / V22bisToken / V18Token / +%% V22Token / V32Token / V34Token / V90Token / +%% V91Token / SynchISDNToken / extensionParameter) +% ensure_modemType({_TokenTag, _Line, Text} = Token) -> +% case Text of +% "v32b" -> v32bis; +% "v22b" -> v22bis; +% "v18" -> v18; +% "v22" -> v22; +% "v32" -> v32; +% "v34" -> v34; +% "v90" -> v90; +% "v91" -> v91; +% "synchisdn" -> synchISDN; +% "sn" -> synchISDN; +% [$x | _] -> ensure_extensionParameter(Token) +% end. + +%% An mtp address is five octets long +ensure_mtpAddress({_TokenTag, _Line, Addr}) -> + %% BUGBUG: validate address + {mtpAddress, Addr}. + +%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter ) +% ensure_muxType({_TokenTag, _Line, Text} = Token) -> +% case Text of +% "h221" -> h221; +% "h223" -> h223; +% "h226" -> h226; +% "v76" -> v76; +% "nx64k" -> nx64k; % v2 +% [$x | _] -> ensure_extensionParameter(Token) +% end. + +%% packagesItem = NAME "-" UINT16 +%% NAME = ALPHA *63(ALPHA / DIGIT / "_" ) +% ensure_packagesItem({TokenTag, Line, Text}) -> +% case string:tokens(Text, [$-]) of +% [Name, Version] -> +% #'PackagesItem'{packageName = ensure_NAME({TokenTag, Line, Name}), +% packageVersion = ensure_uint({TokenTag, Line, Version}, 0, 99)}; +% _ -> +% return_error(Line, {bad_PackagesItem, Text}) +% end. + +%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" ) +%% PackageName = NAME +%% ItemID = NAME +% ensure_pkgdName({TokenTag, Line, Text}) -> +% case string:tokens(Text, [$/]) of +% [Name, Item] -> +% ensure_name_or_star({TokenTag, Line, Name}), +% ensure_name_or_star({TokenTag, Line, Item}), +% Text; +% _ -> +% return_error(Line, {bad_pkgdName, Text}) +% end. + +% ensure_name_or_star({_, _, Name}) when Name == "*" -> +% Name; +% ensure_name_or_star(Name) -> +% ensure_NAME(Name). + + + +%% v2 - start + +% merge_indAudMediaDescriptor({termStateDescr, Val}) -> +% #'IndAudMediaDescriptor'{termStateDescr = Val}; +% merge_indAudMediaDescriptor({streamParm, Val}) -> +% #'IndAudMediaDescriptor'{streams = {oneStream, Val}}; +% merge_indAudMediaDescriptor({streamDescr, Val}) -> +% #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}. + +% merge_indAudLocalControlDescriptor(Parms) -> +% do_merge_indAudLocalControlDescriptor(Parms, +% #'IndAudLocalControlDescriptor'{}). + +% do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) -> +% case Parm of +% modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE -> +% Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'}, +% do_merge_indAudLocalControlDescriptor(Parms, Desc2); +% reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE -> +% Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'}, +% do_merge_indAudLocalControlDescriptor(Parms, Desc2); +% reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE -> +% Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'}, +% do_merge_indAudLocalControlDescriptor(Parms, Desc2); +% {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE -> +% PropParms = [#'IndAudPropertyParm'{name = Val}], +% Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms}, +% do_merge_indAudLocalControlDescriptor(Parms, Desc2); +% {pkgdName, Val} when list(Desc#'IndAudLocalControlDescriptor'.propertyParms) -> +% PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms, +% PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms], +% Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}, +% do_merge_indAudLocalControlDescriptor(Parms, Desc2) +% end; +% do_merge_indAudLocalControlDescriptor([], Desc) -> +% case Desc#'IndAudLocalControlDescriptor'.propertyParms of +% [_ | _] = PropParms -> % List has more then one element +% PropParms2= lists:reverse(PropParms), +% Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2}; +% _ -> +% Desc +% end. + +% ensure_indAudLocalParm(Token) -> +% case Token of +% {safeToken, _Line, "mode"} -> modeToken; +% {safeToken, _Line, "mo"} -> modeToken; +% {safeToken, _Line, "reservedgroup"} -> reservedGroupToken; +% {safeToken, _Line, "rg"} -> reservedGroupToken; +% {safeToken, _Line, "reservedvalue"} -> reservedValueToken; +% {safeToken, _Line, "rv"} -> reservedValueToken; +% PkgdName -> {pkgdName, +% ensure_pkgdName(PkgdName)} +% end. + +% merge_indAudTerminationStateDescriptor({pkgdName, Val}) -> +% PropParm = #'IndAudPropertyParm'{name = Val}, +% #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]}; +% merge_indAudTerminationStateDescriptor(serviceStatesToken) -> +% #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'}; +% merge_indAudTerminationStateDescriptor(bufferToken) -> +% #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}. + + +% merge_indAudEventBufferDescriptor(EventName, SpecParams) -> +% IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName}, +% do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD). + +% do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) -> +% IAEBD; +% do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) -> +% IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID}; +% do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN, +% IAEBD) -> +% %% BUGBUG BUGBUG BUGBUG +% %% This is an ugly hack to allow the eventParamName which only +% %% exists in the text encoding... +% IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}. + + +% ensure_indAudSignalListParm(SIG) when record(SIG, 'Signal') -> +% ensure_indAudSignal(SIG). + +% ensure_indAudSignal(#'Signal'{signalName = SignalName, +% streamID = asn1_NOVALUE, +% sigType = asn1_NOVALUE, +% duration = asn1_NOVALUE, +% notifyCompletion = asn1_NOVALUE, +% keepActive = asn1_NOVALUE, +% sigParList = []}) -> +% #'IndAudSignal'{signalName = SignalName}. + + +% ensure_IADMD({_TokenTag, _Line, +% #'DigitMapDescriptor'{digitMapName = Name, +% digitMapValue = asn1_NOVALUE}}) -> +% #'IndAudDigitMapDescriptor'{digitMapName = Name}. + + +% merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N, +% packageVersion = V}) -> +% #'IndAudPackagesDescriptor'{packageName = N, +% packageVersion = V}. + + +% ensure_indAudTerminationStateParm(Token) -> +% case Token of +% {safeToken, _Line, "servicestates"} -> serviceStatesToken; +% {safeToken, _Line, "si"} -> serviceStatesToken; +% {safeToken, _Line, "buffer"} -> bufferToken; +% {safeToken, _Line, "bf"} -> bufferToken; +% PkgdName -> {pkgdName, +% ensure_pkgdName(PkgdName)} +% end. + + +% %% Types modified by v2: + +% merge_auditDescriptor([]) -> +% #'AuditDescriptor'{}; +% merge_auditDescriptor(Tokens) when list(Tokens) -> +% case lists:keysearch(terminationAudit, 1, Tokens) of +% {value, {terminationAudit, TA}} -> +% case lists:keydelete(terminationAudit, 1, Tokens) of +% [] -> +% #'AuditDescriptor'{auditPropertyToken = TA}; +% AuditTokens -> +% #'AuditDescriptor'{auditToken = AuditTokens, +% auditPropertyToken = TA} +% end; +% false -> +% #'AuditDescriptor'{auditToken = Tokens} +% end; +% merge_auditDescriptor(_) -> +% #'AuditDescriptor'{}. + + +% %% v2 - end + + + +% merge_ServiceChangeParm(Parms) -> +% Required = [serviceChangeReason, serviceChangeMethod], +% merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required). + +% merge_ServiceChangeParm([], SCP, []) -> +% SCP; + +% merge_ServiceChangeParm([], _SCP, Required) -> +% exit({missing_required_serviceChangeParm, Required}); + +% merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE, +% SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); +% merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req) +% when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE -> +% MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId, +% exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId}); + +% merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE, +% SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); +% merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req) +% when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE -> +% Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress, +% exit({not_both_address_mgcid_serviceChangeParm, Val, Addr}); + +% merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); + +% merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); + +% %% REQUIRED (i.e. no default value) +% merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0) +% when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val}, +% Req = lists:delete(serviceChangeReason, Req0), +% merge_ServiceChangeParm(Parms, SCP, Req); + +% merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); + +% %% REQUIRED (i.e. no default value) +% merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0) +% when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined -> +% SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val}, +% Req = lists:delete(serviceChangeMethod, Req0), +% merge_ServiceChangeParm(Parms, SCP, Req); + +% merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE -> +% SCP = SCP0#'ServiceChangeParm'{timeStamp = Val}, +% merge_ServiceChangeParm(Parms, SCP, Req); + +% merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) -> +% merge_ServiceChangeParm(Parms, SCP0, Req); + +% merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) +% when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE -> +% SCI = #'AuditDescriptor'{auditToken = [Val]}, +% SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI}, +% merge_ServiceChangeParm(Parms, SCP, Req); + +% merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) -> +% Val2 = +% case Tag of +% address -> +% SCP#'ServiceChangeParm'.serviceChangeAddress; +% mgc_id -> +% SCP#'ServiceChangeParm'.serviceChangeMgcId; +% profile -> +% SCP#'ServiceChangeParm'.serviceChangeProfile; +% version -> +% SCP#'ServiceChangeParm'.serviceChangeVersion; +% reason -> +% SCP#'ServiceChangeParm'.serviceChangeReason; +% delay -> +% SCP#'ServiceChangeParm'.serviceChangeDelay; +% method -> +% SCP#'ServiceChangeParm'.serviceChangeMethod; +% time_stamp -> +% SCP#'ServiceChangeParm'.timeStamp; +% audit_item -> +% SCP#'ServiceChangeParm'.serviceChangeInfo +% end, +% exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}). + + +% merge_ServiceChangeResParm(Parms) -> +% merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}). + +% merge_ServiceChangeResParm([], SCRP) -> +% SCRP; +% merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE, +% SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> +% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val}, +% merge_ServiceChangeResParm(Parms, SCRP); +% merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> +% MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId, +% exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId}); + +% merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE, +% SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> +% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val}, +% merge_ServiceChangeResParm(Parms, SCRP); +% merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> +% Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress, +% exit({not_both_address_mgcid_servChgReplyParm, Val, Addr}); + +% merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE -> +% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val}, +% merge_ServiceChangeResParm(Parms, SCRP); + +% merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE -> +% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val}, +% merge_ServiceChangeResParm(Parms, SCRP); + +% merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0) +% when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE -> +% SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val}, +% merge_ServiceChangeResParm(Parms, SCRP); + +% merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) -> +% Val2 = +% case Tag of +% address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress; +% mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId; +% profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile; +% version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion; +% time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp +% end, +% exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}). + + +% ensure_serviceChangeMethod({safeToken, _Line, "fl"}) -> +% failover; +% ensure_serviceChangeMethod({safeToken, _Line, "failover"}) -> +% failover; +% ensure_serviceChangeMethod({safeToken, _Line, "fo"}) -> +% forced; +% ensure_serviceChangeMethod({safeToken, _Line, "forced"}) -> +% forced; +% ensure_serviceChangeMethod({safeToken, _Line, "gr"}) -> +% graceful; +% ensure_serviceChangeMethod({safeToken, _Line, "graceful"}) -> +% graceful; +% ensure_serviceChangeMethod({safeToken, _Line, "rs"}) -> +% restart; +% ensure_serviceChangeMethod({safeToken, _Line, "restart"}) -> +% restart; +% ensure_serviceChangeMethod({safeToken, _Line, "dc"}) -> +% disconnected; +% ensure_serviceChangeMethod({safeToken, _Line, "disconnected"}) -> +% disconnected; +% ensure_serviceChangeMethod({safeToken, _Line, "ho"}) -> +% handOff; +% ensure_serviceChangeMethod({safeToken, _Line, "handoff"}) -> +% handOff; +% ensure_serviceChangeMethod({safeToken, Line, Text}) -> +% return_error(Line, {bad_serviceChangeMethod, Text}). + + +ensure_profile({_TokenTag, Line, Text}) -> + case string:tokens(Text, [$/]) of + [Name, Version] -> + Version2 = ensure_version(Version), + #'ServiceChangeProfile'{profileName = Name, version = Version2}; + _ -> + return_error(Line, {bad_profile, Text}) + end. + +ensure_version(Version) -> + ensure_uint(Version, 0, 99). + +% merge_signalRequest(SignalName, PropertyParms) -> +% Sig = #'Signal'{signalName = SignalName}, +% SPL = [], +% do_merge_signalRequest(Sig, PropertyParms, SPL). + +% do_merge_signalRequest(Sig, [H | T], SPL) -> +% case H of +% {stream, StreamId} when Sig#'Signal'.streamID == asn1_NOVALUE -> +% do_merge_signalRequest(Sig#'Signal'{streamID = StreamId}, T, SPL); +% {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE -> +% do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL); +% {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE -> +% do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL); +% {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE -> +% do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL); +% keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE-> +% do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL); +% {other, Name, PP} -> +% SP = #'SigParameter'{sigParameterName = Name, +% value = PP#'PropertyParm'.value, +% extraInfo = PP#'PropertyParm'.extraInfo}, +% do_merge_signalRequest(Sig, T, [SP | SPL]); +% _ -> +% return_error(0, {bad_sigParm, H}) +% end; +% do_merge_signalRequest(Sig, [], SPL) -> +% Sig#'Signal'{sigParList = lists:reverse(SPL)} . + +% %% eventStream = StreamToken EQUAL StreamID +% %% eventOther = eventParameterName parmValue +% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) -> +% {stream, ensure_uint16(Value)}; +% select_stream_or_other("st", Value) -> +% {stream, ensure_uint16(Value)}; +% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) -> +% {stream, ensure_uint16(Value)}; +% select_stream_or_other("stream", Value) -> +% {stream, ensure_uint16(Value)}; +% select_stream_or_other(Name, #'PropertyParm'{value = Value}) -> +% EP = #'EventParameter'{eventParameterName = Name, +% value = Value}, +% {other, EP}. + +% ensure_eventDM({_TokenTag, Line, DMD}) +% when record(DMD, 'DigitMapDescriptor') -> +% Name = DMD#'DigitMapDescriptor'.digitMapName, +% Val = DMD#'DigitMapDescriptor'.digitMapValue, +% if +% Name == asn1_NOVALUE, Val /= asn1_NOVALUE -> +% {'DigitMapValue', Start, Short, Long, Duration, Body} = Val, +% DMV = #'DigitMapValue'{startTimer = Start, +% shortTimer = Short, +% longTimer = Long, +% digitMapBody = Body, +% durationTimer = Duration}, +% {eventDM, {digitMapValue, DMV}}; +% Name /= asn1_NOVALUE, Val == asn1_NOVALUE -> +% {eventDM, {digitMapName, Name}}; +% true -> +% return_error(Line, {bad_eventDM, DMD}) +% end. + +% ensure_DMD({_TokenTag, _Line, DMD}) +% when record(DMD, 'DigitMapDescriptor') -> +% Val2 = +% case DMD#'DigitMapDescriptor'.digitMapValue of +% %% Note that the values of the digitMapBody and durationTimers +% %% are swapped by the scanner (this is done because of a +% %% problem in the flex scanner). +% #'DigitMapValue'{durationTimer = Body, +% digitMapBody = Duration} = DMV -> +% %% Convert to version 1 DigitMapValue +% DMV#'DigitMapValue'{digitMapBody = Body, +% durationTimer = Duration}; +% Other -> +% Other +% end, +% DMD#'DigitMapDescriptor'{digitMapValue = Val2}. + + +% merge_observed_event(ObservedEvents, EventName, TimeStamp) -> +% StreamId = asn1_NOVALUE, +% EPL = [], +% do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL). + +% do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) -> +% do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL); +% do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) -> +% do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]); +% do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) -> +% #'ObservedEvent'{eventName = EventName, +% timeNotation = TimeStamp, +% streamID = StreamID, +% eventParList = lists:reverse(EPL)}. + +% merge_eventSpec(OE) when record(OE, 'ObservedEvent'), +% OE#'ObservedEvent'.timeNotation == asn1_NOVALUE -> +% #'EventSpec'{eventName = OE#'ObservedEvent'.eventName, +% streamID = OE#'ObservedEvent'.streamID, +% eventParList = OE#'ObservedEvent'.eventParList}; +% merge_eventSpec(OE) -> +% return_error(0, {bad_event_spec, OE}). + +% merge_eventParameters(Params) -> +% StreamId = asn1_NOVALUE, +% EPL = [], +% RA = #'RequestedActions'{}, +% HasA = no, +% do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) . + +% do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) -> +% case H of +% keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE -> +% RA2 = RA#'RequestedActions'{keepActive = true}, +% do_merge_eventParameters(T, StreamId, EPL, RA2, yes); +% {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE -> +% RA2 = RA#'RequestedActions'{signalsDescriptor = SD, +% secondEvent = SED}, +% do_merge_eventParameters(T, StreamId, EPL, RA2, yes); +% {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE -> +% RA2 = RA#'RequestedActions'{eventDM = DM}, +% do_merge_eventParameters(T, StreamId, EPL, RA2, yes); +% {stream, NewStreamId} when StreamId == asn1_NOVALUE -> +% do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA); +% {other, PP} when record(PP, 'PropertyParm') -> +% EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, +% value = PP#'PropertyParm'.value, +% extraInfo = PP#'PropertyParm'.extraInfo}, +% do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); +% {other, EP} when record(EP, 'EventParameter') -> +% do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA); +% _ -> +% return_error(0, {bad_eventParameter, H}) +% end; +% do_merge_eventParameters([], StreamId, EPL, RA, yes) -> +% #'RequestedEvent'{streamID = StreamId, +% eventAction = RA, +% evParList = lists:reverse(EPL)}; +% do_merge_eventParameters([], StreamId, EPL, _RA, no) -> +% #'RequestedEvent'{streamID = StreamId, +% eventAction = asn1_NOVALUE, +% evParList = lists:reverse(EPL)}. + +% merge_secondEventParameters(Params) -> +% StreamId = asn1_NOVALUE, +% EPL = [], +% SRA = #'SecondRequestedActions'{}, +% HasA = no, +% do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) . + +% do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) -> +% case H of +% keepActive when SRA#'SecondRequestedActions'.keepActive == asn1_NOVALUE -> +% SRA2 = SRA#'SecondRequestedActions'{keepActive = true}, +% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); +% {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor == asn1_NOVALUE -> +% SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD}, +% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); +% {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM == asn1_NOVALUE -> +% SRA2 = SRA#'SecondRequestedActions'{eventDM = DM}, +% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes); +% {stream, NewStreamId} when StreamId == asn1_NOVALUE -> +% do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA); +% {other, PP} when record(PP, 'PropertyParm') -> +% EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name, +% value = PP#'PropertyParm'.value, +% extraInfo = PP#'PropertyParm'.extraInfo}, +% do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); +% {other, EP} when record(EP, 'EventParameter') -> +% do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA); +% _ -> +% return_error(0, {bad_secondEventParameter, H}) +% end; +% do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) -> +% #'SecondRequestedEvent'{streamID = StreamId, +% eventAction = SRA, +% evParList = lists:reverse(EPL)}; +% do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) -> +% #'SecondRequestedEvent'{streamID = StreamId, +% eventAction = asn1_NOVALUE, +% evParList = lists:reverse(EPL)}. + +% %% terminationID = "ROOT" / pathName / "$" / "*" +% %% Total length of pathName must not exceed 64 chars. +% %% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) +% %% ["@" pathDomainName ] +% %% ABNF allows two or more consecutive "." although it is meaningless +% %% in a path domain name. +% %% pathDomainName = (ALPHA / DIGIT / "*" ) +% %% *63(ALPHA / DIGIT / "-" / "*" / ".") +% ensure_terminationID({safeToken, _Line, LowerText}) -> +% %% terminationID = "ROOT" / pathName / "$" / "*" +% decode_term_id(LowerText, false, [], []). + +% decode_term_id([H | T], Wild, Id, Component) -> +% case H of +% $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []); +% $* -> decode_term_id(T, true, Id, [?megaco_all | Component]); +% $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]); +% _ -> decode_term_id(T, Wild, Id, [H | Component]) +% end; +% decode_term_id([], Wild, Id, Component) -> +% Id2 = [lists:reverse(Component) | Id], +% #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}. + +ensure_pathName({_TokenTag, _Line, Text}) -> + Text. %% BUGBUG: ensure values + +%% TimeStamp = Date "T" Time ; per ISO 8601:1988 +%% Date = 8(DIGIT) ; Date = yyyymmdd +%% Time = 8(DIGIT) ; Time = hhmmssss +% ensure_timeStamp({'TimeStampToken', Line, Text}) -> +% case string:tokens(Text, [$T, $t]) of +% [Date, Time] -> +% #'TimeNotation'{date = Date, time = Time}; +% _ -> +% return_error(Line, {bad_timeStamp, Text}) +% end. + +% ensure_transactionID(TransId) -> +% ensure_uint32(TransId). + +% %% transactionAck = transactionID / (transactionID "-" transactionID) +% ensure_transactionAck({safeToken, _Line, Text}) -> +% case string:tokens(Text, [$-]) of +% [Id] -> +% #'TransactionAck'{firstAck = ensure_transactionID(Id)}; +% [Id, Id2] -> +% #'TransactionAck'{firstAck = ensure_transactionID(Id), +% lastAck = ensure_transactionID(Id2)} +% end. + +% merge_action_requests(CtxId, Items) -> +% CtxReq = #'ContextRequest'{}, +% CtxAuditReq = asn1_NOVALUE, +% CmdReq = [], +% TopReq = [], +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, Items). + +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, [H | T]) -> +% case H of +% _ when record(H, 'CommandRequest') -> +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, [H | CmdReq], TopReq, T); + +% {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE -> +% CtxReq2 = CtxReq#'ContextRequest'{priority = Int}, +% do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq, +% TopReq, T); +% {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE -> +% CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool}, +% do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq, +% TopReq, T); +% {topology, Desc} -> +% TopReq2 = Desc ++ TopReq, %% OTP-4088 +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, +% TopReq2, T); + +% {contextAudit, CAs} -> +% CtxAuditReq2 = merge_context_attr_audit_request(CtxAuditReq, CAs), +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq2, CmdReq, +% TopReq, T) + +% end; +% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, []) -> +% #'ActionRequest'{contextId = CtxId, +% contextRequest = strip_contextRequest(CtxReq, TopReq), +% contextAttrAuditReq = strip_contextAttrAuditRequest(CtxAuditReq), +% commandRequests = lists:reverse(CmdReq)}. + + +% merge_context_attr_audit_request(asn1_NOVALUE, CAs) -> +% merge_context_attr_audit_request(#'ContextAttrAuditRequest'{}, CAs); +% merge_context_attr_audit_request(CAAR, [H|T]) -> +% CAAR2 = +% case H of +% priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE -> +% CAAR#'ContextAttrAuditRequest'{priority = 'NULL'}; + +% priorityAudit -> +% Prio = CAAR#'ContextAttrAuditRequest'.priority, +% exit({only_once, priorityAudit, Prio}); + +% emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE -> +% CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'}; + +% emergencyAudit -> +% Em = CAAR#'ContextAttrAuditRequest'.emergency, +% exit({only_once, emergencyAudit, Em}); + +% topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE -> +% CAAR#'ContextAttrAuditRequest'{topology = 'NULL'}; + +% topologyAudit -> +% Top = CAAR#'ContextAttrAuditRequest'.topology, +% exit({only_once, topologyAudit, Top}) + +% end, +% merge_context_attr_audit_request(CAAR2, T); +% merge_context_attr_audit_request(CAAR, []) -> +% CAAR. + +% %% OTP-5085: +% %% In order to solve a problem in the parser, the error descriptor +% %% has been put last in the non-empty commandReplyList, if it is not +% %% asn1_NOVALUE +% merge_action_reply(ReplyList) -> +% CtxReq = #'ContextRequest'{}, +% TopReq = [], +% CmdList = [], +% case lists:reverse(ReplyList) of +% [ED|RL2] when record(ED, 'ErrorDescriptor') -> +% AR = do_merge_action_reply(lists:reverse(RL2), +% CtxReq, TopReq, CmdList), +% AR#'ActionReply'{errorDescriptor = ED}; +% _ -> +% do_merge_action_reply(ReplyList, CtxReq, TopReq, CmdList) +% end. + +% do_merge_action_reply([H | T], CtxReq, TopReq, CmdList) -> +% case H of +% {command, Cmd} -> +% do_merge_action_reply(T, CtxReq, TopReq, [Cmd | CmdList]); +% {context, Ctx} -> +% case Ctx of +% {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE -> +% CtxReq2 = CtxReq#'ContextRequest'{priority = Int}, +% do_merge_action_reply(T, CtxReq2, TopReq, CmdList); +% {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE -> +% CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool}, +% do_merge_action_reply(T, CtxReq2, TopReq, CmdList); +% {topology, Desc} -> +% TopReq2 = Desc ++ TopReq, %% OTP-4088 +% do_merge_action_reply(T, CtxReq, TopReq2, CmdList) +% end +% end; +% do_merge_action_reply([], CtxReq, TopReq, CmdList) -> +% #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq), +% commandReply = lists:reverse(CmdList)}. + +% strip_contextRequest(R, TopReq) +% when R#'ContextRequest'.priority == asn1_NOVALUE, +% R#'ContextRequest'.emergency == asn1_NOVALUE, +% TopReq == [] -> +% asn1_NOVALUE; +% strip_contextRequest(R, []) -> +% R#'ContextRequest'{topologyReq = asn1_NOVALUE}; +% strip_contextRequest(R, TopReq) -> +% R#'ContextRequest'{topologyReq = TopReq}. %% OTP-4088 + + +% strip_contextAttrAuditRequest(R) +% when R#'ContextAttrAuditRequest'.priority == asn1_NOVALUE, +% R#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE, +% R#'ContextAttrAuditRequest'.topology == asn1_NOVALUE -> +% asn1_NOVALUE; +% strip_contextAttrAuditRequest(R) -> +% R. + +% make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) -> +% Req = #'CommandRequest'{command = {CmdTag, Cmd}}, +% case Text of +% [$w, $- | _] -> +% Req#'CommandRequest'{wildcardReturn = 'NULL'}; +% [$o, $-, $w, $- | _] -> +% Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'}; +% [$o, $- | _] -> +% Req#'CommandRequest'{optional = 'NULL'}; +% _ -> +% Req +% end. + +% merge_terminationAudit(AuditReturnParameters) -> +% lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])). + +% do_merge_terminationAudit([H| T], ARPs, AuditItems) -> +% case H of +% {auditReturnItem, AuditItem} -> +% do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]); +% AuditReturnParameter -> +% do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems) +% end; +% do_merge_terminationAudit([], AuditReturnParameters, []) -> +% AuditReturnParameters; +% do_merge_terminationAudit([], AuditReturnParameters, AuditItems) -> +% AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems}, +% AuditReturnParameter = {emptyDescriptors, AuditDescriptor}, +% [AuditReturnParameter | AuditReturnParameters]. + +% merge_mediaDescriptor(MediaParms) -> +% do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []). + +% do_merge_mediaDescriptor([H | T], TS, One, Multi) -> +% case H of +% {streamParm, Parm} when Multi == [] -> +% do_merge_mediaDescriptor(T, TS, [Parm | One], Multi); +% {streamDescriptor, Desc} when One == [] -> +% do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]); +% {termState, TS2} when TS == asn1_NOVALUE -> +% do_merge_mediaDescriptor(T, TS2, One, Multi); +% _ -> +% return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]}) +% end; +% do_merge_mediaDescriptor([], TS, One, Multi) -> +% if +% One == [], Multi == [] -> +% #'MediaDescriptor'{streams = asn1_NOVALUE, +% termStateDescr = TS}; +% One /= [], Multi == [] -> +% #'MediaDescriptor'{streams = {oneStream, merge_streamParms(One)}, +% termStateDescr = TS}; +% One == [], Multi /= [] -> +% #'MediaDescriptor'{streams = {multiStream, lists:reverse(Multi)}, +% termStateDescr = TS} +% end. + +% merge_streamParms(TaggedStreamParms) -> +% SP = #'StreamParms'{}, +% do_merge_streamParms(TaggedStreamParms, SP). + +% do_merge_streamParms([{Tag, D} | T] = All, SP) -> +% case Tag of +% local when SP#'StreamParms'.localDescriptor == asn1_NOVALUE -> +% do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D}); +% remote when SP#'StreamParms'.remoteDescriptor == asn1_NOVALUE -> +% do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D}); +% control -> +% LCD = +% case SP#'StreamParms'.localControlDescriptor of +% asn1_NOVALUE -> +% #'LocalControlDescriptor'{propertyParms = []}; +% PrevLCD -> +% PrevLCD +% end, +% LCD2 = do_merge_control_streamParms(D, LCD), +% do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2}); +% _ -> +% return_error(0, {do_merge_streamParms, [All, SP]}) +% end; +% do_merge_streamParms([], SP) when record(SP#'StreamParms'.localControlDescriptor, 'LocalControlDescriptor') -> +% LCD = SP#'StreamParms'.localControlDescriptor, +% PP = LCD#'LocalControlDescriptor'.propertyParms, +% LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)}, +% SP#'StreamParms'{localControlDescriptor = LCD2}; +% do_merge_streamParms([], SP) -> +% SP. + + +% do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) -> +% case SubTag of +% group when LCD#'LocalControlDescriptor'.reserveGroup == asn1_NOVALUE -> +% LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD}, +% do_merge_control_streamParms(T, LCD2); +% value when LCD#'LocalControlDescriptor'.reserveValue == asn1_NOVALUE -> +% LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD}, +% do_merge_control_streamParms(T, LCD2); +% mode when LCD#'LocalControlDescriptor'.streamMode == asn1_NOVALUE -> +% LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD}, +% do_merge_control_streamParms(T, LCD2); +% prop -> +% PP = LCD#'LocalControlDescriptor'.propertyParms, +% LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]}, +% do_merge_control_streamParms(T, LCD2); +% _ -> +% return_error(0, {do_merge_control_streamParms, [All, LCD]}) +% end; +% do_merge_control_streamParms([], LCD) -> +% LCD. + +% merge_terminationStateDescriptor(Parms) -> +% TSD = #'TerminationStateDescriptor'{propertyParms = []}, +% do_merge_terminationStateDescriptor(Parms, TSD). + +% do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) -> +% case Tag of +% serviceState when TSD#'TerminationStateDescriptor'.serviceState == asn1_NOVALUE -> +% TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val}, +% do_merge_terminationStateDescriptor(T, TSD2); +% eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl == asn1_NOVALUE-> +% TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val}, +% do_merge_terminationStateDescriptor(T, TSD2); +% propertyParm -> +% PP = TSD#'TerminationStateDescriptor'.propertyParms, +% TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]}, +% do_merge_terminationStateDescriptor(T, TSD2) +% end; +% do_merge_terminationStateDescriptor([], TSD) -> +% PP = TSD#'TerminationStateDescriptor'.propertyParms, +% TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}. + +% ensure_prop_groups({_TokenTag, _Line, Text}) -> +% Group = [], +% Groups = [], +% parse_prop_name(Text, Group, Groups). + +% parse_prop_name([Char | Rest] = All, Group, Groups) -> +% case ?classify_char(Char) of +% white_space -> +% parse_prop_name(Rest, Group, Groups); +% end_of_line -> +% parse_prop_name(Rest, Group, Groups); +% _ -> +% Name = [], +% do_parse_prop_name(All, Name, Group, Groups) +% end; +% parse_prop_name([] = All, Group, Groups) -> +% Name = [], +% do_parse_prop_name(All, Name, Group, Groups). + +% do_parse_prop_name([Char | Rest], Name, Group, Groups) -> +% case ?classify_char(Char) of +% safe_char -> +% do_parse_prop_name(Rest, [Char | Name], Group, Groups); +% rest_char when Char == $=, Name /= [] -> +% %% Now we have a complete name +% if +% Name == "v", Group /= [] -> +% %% v= is a property group delimiter, +% %% lets create yet another property group. +% Groups2 = [lists:reverse(Group) | Groups], +% Group2 = [], +% parse_prop_value(Rest, Name, Group2, Groups2); +% true -> +% %% Use current property group +% parse_prop_value(Rest, Name, Group, Groups) +% end; +% _ -> +% return_error(0, {bad_prop_name, lists:reverse(Name), Char}) +% end; +% do_parse_prop_name([], [], [], Groups) -> +% lists:reverse(Groups); +% do_parse_prop_name([], [], Group, Groups) -> +% Group2 = lists:reverse(Group), +% lists:reverse([Group2 | Groups]); +% do_parse_prop_name([], Name, Group, Groups) when Name /= [] -> +% %% Assume end of line +% Value = [], +% PP = make_prop_parm(Name, Value), +% Group2 = lists:reverse([PP | Group]), +% lists:reverse([Group2 | Groups]). + +% parse_prop_value(Chars, Name, Group, Groups) -> +% Value = [], +% do_parse_prop_value(Chars, Name, Value, Group, Groups). + +% do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) -> +% case ?classify_char(Char) of +% end_of_line -> +% %% Now we have a complete "name=value" pair +% PP = make_prop_parm(Name, Value), +% parse_prop_name(Rest, [PP | Group], Groups); +% _ -> +% do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups) +% end; +% do_parse_prop_value([], Name, Value, Group, Groups) -> +% %% Assume end of line +% PP = make_prop_parm(Name, Value), +% Group2 = lists:reverse([PP | Group]), +% lists:reverse([Group2 | Groups]). + +% make_prop_parm(Name, Value) -> +% #'PropertyParm'{name = lists:reverse(Name), +% value = [lists:reverse(Value)]}. + +ensure_uint({_TokenTag, Line, Val}, Min, Max) when is_integer(Val) -> + if + is_integer(Min) andalso (Val >= Min) -> + if + is_integer(Max) andalso (Val =< Max) -> + Val; + Max =:= infinity -> + Val; + true -> + return_error(Line, {too_large_integer, Val, Max}) + end; + true -> + return_error(Line, {too_small_integer, Val, Min}) + end; +ensure_uint({TokenTag, Line, Text}, Min, Max) -> + case catch list_to_integer(Text) of + {'EXIT', _} -> + return_error(Line, {not_an_integer, Text}); + Val when is_integer(Val) -> + ensure_uint({TokenTag, Line, Val}, Min, Max) + end; +ensure_uint(Val, Min, Max) -> + ensure_uint({uint, 0, Val}, Min, Max). + +ensure_uint16(Int) -> + ensure_uint(Int, 0, 65535). + +% ensure_uint32(Int) -> +% ensure_uint(Int, 0, 4294967295) . + +%% OTP-4710 +ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $x |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []); +ensure_hex([$0, $X |Chars], Min, Max) -> + ensure_uint(length(Chars), Min, Max), + hex_to_int(Chars, []). + +%% OTP-4710 +hex_to_int([], Acc) -> + lists:reverse(Acc); +hex_to_int([Char1,Char2|Tail], Acc) -> + Int1 = hchar_to_int(Char1), + Int2 = hchar_to_int(Char2), + Val = Int2 bor (Int1 bsl 4), + hex_to_int(Tail, [Val| Acc]); +hex_to_int([Char], Acc) -> + Int = hchar_to_int(Char), + lists:reverse([Int|Acc]). + +hchar_to_int(Char) when $0 =< Char, Char =< $9 -> + Char - $0; +hchar_to_int(Char) when $A =< Char, Char =< $F -> + Char - $A + 10; % OTP-4710 +hchar_to_int(Char) when $a =< Char, Char =< $f -> + Char - $a + 10. % OTP-4710 + +% value_of({_TokenTag, _Line, Text}) -> +% Text. + + +% d(F) -> +% d(F, []). + +% d(F, A) -> +% d(get(dbg), F, A). + +% d(true, F, A) -> +% io:format("~p:" ++ F ++ "~n", [?MODULE|A]); +% d(_, _, _) -> +% ok. + |