1
%% ``The contents of this file are subject to the Erlang Public License,
2
%% Version 1.1, (the "License"); you may not use this file except in
3
%% compliance with the License. You should have received a copy of the
4
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
18
%%----------------------------------------------------------------------
19
%% Purpose : Define semantic text parser actions
20
%%----------------------------------------------------------------------
23
-include_lib("megaco/include/megaco.hrl").
24
-include_lib("megaco/include/megaco_message_prev3c.hrl").
25
-include("megaco_text_tokens.hrl").
27
make_safe_token({_TokenTag, Line, Text}) ->
28
{safeToken, Line, Text}.
30
ensure_value({safeToken, _Line, Text}) ->
32
ensure_value({'QuotedChars', _Line, Text}) ->
34
ensure_value(Text) when list(Text) ->
35
Text. %% BUGBUG: ensure length
37
%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
38
ensure_NAME({_TokenTag, _Line, Text}) ->
39
Text. %% BUGBUG: ensure length and chars
41
ensure_requestID({safeToken, _Line, "*"}) ->
42
?megaco_all_request_id;
43
ensure_requestID(RequestId) ->
44
ensure_uint32(RequestId).
46
ensure_streamID(StreamId) ->
47
ensure_uint16(StreamId).
49
ensure_auth_header(SpiToken, SnToken, AdToken) ->
50
Spi = ensure_hex(SpiToken, 8, 8),
51
Sn = ensure_hex(SnToken, 8, 8),
52
Ad = ensure_hex(AdToken, 24, 64),
53
#'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
55
%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
56
%% ContextID = (UINT32 / "*" / "-" / "$")
57
ensure_contextID({_TokenTag, Line, Text}) ->
59
"*" -> ?megaco_all_context_id;
60
"-" -> ?megaco_null_context_id;
61
"\$" -> ?megaco_choose_context_id;
63
CID = ensure_uint32(Int),
66
(CID =/= 16#FFFFFFFE) and
67
(CID =/= 16#FFFFFFFF) ->
70
return_error(Line, {bad_ContextID, CID})
74
ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
75
Addr = ensure_ip4addr(Addr0),
76
{ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
77
ensure_domainAddress([colon,colon], Port) ->
78
Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
79
{ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
80
ensure_domainAddress(Addr0, Port) ->
81
Addr = ensure_ip6addr(Addr0),
82
{ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
85
ensure_ip4addr({TokenTag, Line, Addr}) ->
86
case string:tokens(Addr, [$.]) of
88
A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
89
A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
90
A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
91
A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
94
return_error(Line, {bad_IP4address, Addr})
98
ensure_ip6addr([colon,colon|T]) ->
99
[H1|T1] = lists:reverse(T),
100
case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
101
{true, A} when length(A) == 16 ->
103
{true, B} when length(B) < 16 ->
104
lists:duplicate(16 - length(B), 0) ++ B;
106
throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
109
case lists:reverse(L) of
111
case do_ensure_ip6addr(T, true, [], 1) of
112
{true, A} when length(A) == 16 ->
114
{true, B} when length(B) < 16 ->
115
B ++ lists:duplicate(16 - length(B), 0);
117
throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
119
[H|L1] -> % A (last element) could be an ip4 address
120
case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
121
{false, A} when length(A) == 16 ->
123
%% allow a pad even if the address is full (i.e. 16)
124
{true, B} when length(B) =< 17 ->
125
do_ensure_ip6addr_padding(B, 0);
127
throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
133
do_ensure_ip6addr([], Pad, Acc, _) ->
134
{Pad, lists:flatten(Acc)};
135
do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
136
do_ensure_ip6addr(T, true, [pad|Acc], Line);
137
do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
138
return_error(Line, {bad_mid_duplicate_padding, T, Acc});
139
do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
140
do_ensure_ip6addr(T, Pad, Acc, Line);
141
do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
142
do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
144
do_ensure_ip6addr_padding([], _) ->
146
do_ensure_ip6addr_padding([pad|T], N) ->
147
lists:duplicate(16 - (N + length(T)), 0) ++ T;
148
do_ensure_ip6addr_padding([H|T], N) ->
149
[H|do_ensure_ip6addr_padding(T, N+1)].
151
ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
152
case string:tokens(Addr, [$.]) of
154
A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
155
A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
156
A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
157
A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
162
%% %% Here we should test for hexseq
163
%% return_error(Line, {bad_IP4address, Addr})
166
ensure_hex4({_TokenTag, Line, Hex4})
167
when length(Hex4) =< 4, length(Hex4) > 0 ->
168
case (catch do_ensure_hex4(Hex4)) of
169
IL when list(IL), length(IL) == 2 ->
172
return_error(Line, {bad_hex4, Hex4, Error})
175
do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
177
do_ensure_hex4([H2, H3, H4]) ->
178
hex_to_int([$0, H2, H3, H4], []);
179
do_ensure_hex4([H3, H4]) ->
180
hex_to_int([$0, $0, H3, H4], []);
181
do_ensure_hex4([H4]) ->
182
hex_to_int([$0, $0, $0, H4], []).
184
ensure_domainName({_TokenTag, _Line, Name}, Port) ->
185
%% BUGBUG: validate name
186
{domainName, #'DomainName'{name = Name, portNumber = Port}}.
188
%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
189
ensure_extensionParameter({_TokenTag, Line, Text}) ->
195
return_error(Line, {bad_extension_parameter, Text});
197
{extension_parameter, Text}
200
return_error(Line, {bad_extension_parameter, Text})
203
ensure_message(MegacopToken, MID, Body) ->
204
#'ServiceChangeProfile'{profileName = Name,
206
ensure_profile(MegacopToken),
209
#'Message'{version = Version, mId = MID, messageBody = Body};
211
#'Message'{version = Version, mId = MID, messageBody = Body}
216
%% As of corr 1 ModemDescriptor has been deprecated.
217
%% and since this functon is only used when creating
218
%% a ModemDescriptor, iit is removed.
219
%% modemType = (V32bisToken / V22bisToken / V18Token /
220
%% V22Token / V32Token / V34Token / V90Token /
221
%% V91Token / SynchISDNToken / extensionParameter)
222
%% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
232
%% "synchisdn" -> synchISDN;
233
%% "sn" -> synchISDN;
234
%% [$x | _] -> ensure_extensionParameter(Token)
237
%% An mtp address is five octets long
238
ensure_mtpAddress({_TokenTag, _Line, Addr}) ->
239
%% BUGBUG: validate address
242
%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
243
ensure_muxType({_TokenTag, _Line, Text} = Token) ->
249
"nx64k" -> nx64k; % v2
250
[$x | _] -> ensure_extensionParameter(Token)
253
%% packagesItem = NAME "-" UINT16
254
%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
255
ensure_packagesItem({TokenTag, Line, Text}) ->
256
case string:tokens(Text, [$-]) of
258
#'PackagesItem'{packageName = ensure_NAME({TokenTag, Line, Name}),
259
packageVersion = ensure_uint({TokenTag, Line, Version}, 0, 99)};
261
return_error(Line, {bad_PackagesItem, Text})
264
%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
265
%% PackageName = NAME
267
ensure_pkgdName({TokenTag, Line, Text}) ->
268
case string:tokens(Text, [$/]) of
270
ensure_name_or_star({TokenTag, Line, Name}),
271
ensure_name_or_star({TokenTag, Line, Item}),
274
return_error(Line, {bad_pkgdName, Text})
277
ensure_name_or_star({_, _, Name}) when Name == "*" ->
279
ensure_name_or_star(Name) ->
286
merge_indAudMediaDescriptor(Vals) ->
287
%% d("merge_indAudMediaDescriptor -> entry with"
288
%% "~n Vals: ~p", [Vals]),
289
merge_indAudMediaDescriptor(Vals, #'IndAudMediaDescriptor'{}).
291
merge_indAudMediaDescriptor(
292
[], #'IndAudMediaDescriptor'{streams = Streams1} = D) ->
293
%% d("merge_indAudMediaDescriptor -> entry with"
295
%% "~n D: ~p", [Streams1, D]),
298
{multiStream, Descs} ->
299
{multiStream, lists:reverse(Descs)};
303
D#'IndAudMediaDescriptor'{streams = Streams2};
304
merge_indAudMediaDescriptor([{termStateDescr, Val}|Vals], D)
305
when D#'IndAudMediaDescriptor'.termStateDescr == asn1_NOVALUE ->
306
%% d("merge_indAudMediaDescriptor(termStateDescr) -> entry with"
308
%% "~n D: ~p", [Val, D]),
309
D2 = #'IndAudMediaDescriptor'{termStateDescr = Val},
310
merge_indAudMediaDescriptor(Vals, D2);
311
merge_indAudMediaDescriptor([{streamParm, Val}|Vals], D)
312
when D#'IndAudMediaDescriptor'.streams == asn1_NOVALUE ->
313
%% d("merge_indAudMediaDescriptor(streamParm) -> entry with"
315
%% "~n D: ~p", [Val, D]),
316
D2 = #'IndAudMediaDescriptor'{streams = {oneStream, Val}},
317
merge_indAudMediaDescriptor(Vals, D2);
318
merge_indAudMediaDescriptor([{streamDescr, Val}|Vals], D)
319
when D#'IndAudMediaDescriptor'.streams == asn1_NOVALUE ->
320
%% d("merge_indAudMediaDescriptor(streamDescr) -> entry with"
322
%% "~n D: ~p", [Val, D]),
323
D2 = #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}},
324
merge_indAudMediaDescriptor(Vals, D2);
325
merge_indAudMediaDescriptor([{streamDescr, Val}|Vals],
326
#'IndAudMediaDescriptor'{streams = Streams1} = D1) ->
327
%% d("merge_indAudMediaDescriptor() -> entry with"
330
%% "~n D1: ~p", [Val, Streams1, D1]),
333
{multiStream, Descs} ->
334
{multiStream, [Val|Descs]};
336
return_error(0, {bad_IndAudMediaDescriptor_streamDescr,
339
D2 = D1#'IndAudMediaDescriptor'{streams = Streams2},
340
merge_indAudMediaDescriptor(Vals, D2);
341
merge_indAudMediaDescriptor([{Tag, Val}|_], D) ->
342
%% d("merge_indAudMediaDescriptor -> entry with"
345
%% "~n D: ~p", [Tag, Val, D]),
348
return_error(0, {bad_IndAudMediaDescriptor_termStateDescr,
349
Val, D#'IndAudMediaDescriptor'.termStateDescr});
351
return_error(0, {bad_IndAudMediaDescriptor_streamParm,
352
Val, D#'IndAudMediaDescriptor'.streams});
354
return_error(0, {bad_IndAudMediaDescriptor_streamDescr,
355
Val, D#'IndAudMediaDescriptor'.streams});
357
return_error(0, {bad_IndAudMediaDescriptor_tag, Tag, Val})
360
merge_indAudLocalControlDescriptor(Parms) ->
361
merge_indAudLocalControlDescriptor(Parms,
362
#'IndAudLocalControlDescriptor'{},
365
merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP)
366
when (D#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE) and
367
(D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) ->
368
%% d("merge_indAudLocalControlDescriptor(modeToken,1) -> entry when"
370
%% "~n PP: ~p", [D, PP]),
371
D2 = D#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
372
merge_indAudLocalControlDescriptor(Parms, D2, PP);
374
merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP)
375
when (D#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE) ->
376
%% d("merge_indAudLocalControlDescriptor(modeToken,2) -> entry when"
378
%% "~n PP: ~p", [D, PP]),
379
merge_indAudLocalControlDescriptor(Parms, D, PP);
381
merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP)
382
when (D#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE) and
383
(D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) ->
384
%% d("merge_indAudLocalControlDescriptor(mode,1) -> entry when"
387
%% "~n PP: ~p", [Val, D, PP]),
391
D#'IndAudLocalControlDescriptor'{streamModeSel = Val2};
393
D#'IndAudLocalControlDescriptor'{streamModeSel = Val2}
395
merge_indAudLocalControlDescriptor(Parms, D2, PP);
397
merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP)
398
when (D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) ->
399
%% d("merge_indAudLocalControlDescriptor(mode,2) -> entry when"
402
%% "~n PP: ~p", [Val, D, PP]),
406
D#'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE,
407
streamModeSel = Val2};
409
D#'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE,
410
streamModeSel = Val2}
412
merge_indAudLocalControlDescriptor(Parms, D2, PP);
414
merge_indAudLocalControlDescriptor([reservedGroupToken | Parms], D, PP)
415
when D#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
416
%% d("merge_indAudLocalControlDescriptor(reservedGroupToken) -> entry when"
418
%% "~n PP: ~p", [D, PP]),
419
D2 = D#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
420
merge_indAudLocalControlDescriptor(Parms, D2, PP);
422
merge_indAudLocalControlDescriptor([reservedValueToken | Parms], D, PP)
423
when D#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
424
%% d("merge_indAudLocalControlDescriptor(reservedValueToken) -> entry when"
426
%% "~n PP: ~p", [D, PP]),
427
D2 = D#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
428
merge_indAudLocalControlDescriptor(Parms, D2, PP);
430
%% This is really wierd in the standard, so at this point this is the
431
%% best I can do... BUGBUG BUGBUG BUGBUG
433
merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, asn1_NOVALUE) ->
434
%% d("merge_indAudLocalControlDescriptor(name) -> entry when"
436
%% "~n D: ~p", [Val, D]),
437
PP = #'IndAudPropertyParm'{name = Val},
438
merge_indAudLocalControlDescriptor(Parms, D, PP);
440
merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP)
441
when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
442
%% d("merge_indAudLocalControlDescriptor(name) -> entry when"
444
%% "~n D: ~p", [Val, D]),
445
D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP]},
446
PP2 = #'IndAudPropertyParm'{name = Val},
447
merge_indAudLocalControlDescriptor(Parms, D2, PP2);
449
merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP) ->
450
%% d("merge_indAudLocalControlDescriptor(name) -> entry when"
452
%% "~n D: ~p", [Val, D]),
453
PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
454
D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP|PPs]},
455
PP2 = #'IndAudPropertyParm'{name = Val},
456
merge_indAudLocalControlDescriptor(Parms, D2, PP2);
458
%% BUGBUG BUGBUG I cannot construct a proper IndAudPropertyParm with
459
%% just the prop (the mandatory name part is missing), so for now I
460
%% assume that it this has been used, then the name part
461
%% (pkgdName) must precide it?
462
merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP)
463
when (PP =/= asn1_NOVALUE) and
464
(D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE) ->
465
%% d("merge_indAudLocalControlDescriptor(prop,1) -> entry when"
468
%% "~n PP: ~p", [Val, D, PP]),
469
PP2 = PP#'IndAudPropertyParm'{propertyParms = Val},
470
D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2]},
471
merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE);
473
merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP)
474
when (PP =/= asn1_NOVALUE) and
475
is_list(D#'IndAudLocalControlDescriptor'.propertyParms) ->
476
%% d("merge_indAudLocalControlDescriptor(prop,2) -> entry when"
479
%% "~n PP: ~p", [Val, D, PP]),
480
PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
481
PP2 = PP#'IndAudPropertyParm'{propertyParms = Val},
482
D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2|PPs]},
483
merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE);
485
merge_indAudLocalControlDescriptor([H | _T], _D, _PP) ->
486
return_error(0, {bad_indAudLocalControlDescriptor_parm, H});
488
merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE)
489
when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
490
%% d("merge_indAudLocalControlDescriptor -> entry when done with"
493
merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE) ->
494
%% d("merge_indAudLocalControlDescriptor -> entry when done with"
496
PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
497
PropParms2 = lists:reverse(PPs),
498
D#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
499
merge_indAudLocalControlDescriptor([], D, PP)
500
when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
501
%% d("merge_indAudLocalControlDescriptor -> entry when done with"
503
%% "~n PP: ~p", [D, PP]),
504
D#'IndAudLocalControlDescriptor'{propertyParms = [PP]};
505
merge_indAudLocalControlDescriptor([], D, PP) ->
506
%% d("merge_indAudLocalControlDescriptor -> entry when done with"
508
%% "~n PP: ~p", [D, PP]),
509
PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
510
PPs2 = lists:reverse([PP|PPs]),
511
D#'IndAudLocalControlDescriptor'{propertyParms = PPs2}.
514
merge_indAudTerminationStateDescriptor({name, Val}) ->
515
PropParm = #'IndAudPropertyParm'{name = Val},
516
#'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
517
%% BUGBUG BUGBUG BUGBUG
518
merge_indAudTerminationStateDescriptor({prop, Val}) ->
519
exit({incomplete_propertyParm_in_indAudTerminationStateDescriptor, Val});
520
merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
521
#'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
522
merge_indAudTerminationStateDescriptor({serviceStates, {equal, Val}}) ->
523
#'IndAudTerminationStateDescriptor'{serviceStateSel = Val};
524
merge_indAudTerminationStateDescriptor({serviceStates, {inequal, Val}}) ->
525
#'IndAudTerminationStateDescriptor'{serviceStateSel = Val};
526
merge_indAudTerminationStateDescriptor(bufferToken) ->
527
#'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
530
merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
531
IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
532
do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
534
do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
536
do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
537
IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
538
do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN,
540
%% BUGBUG BUGBUG BUGBUG
541
%% This is an ugly hack to allow the eventParamName which only
542
%% exists in the text encoding...
543
IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
546
ensure_indAudSignalListParm(SIG) when record(SIG, 'Signal') ->
547
ensure_indAudSignal(SIG).
549
ensure_indAudSignal(#'Signal'{signalName = SignalName,
551
sigType = asn1_NOVALUE,
552
duration = asn1_NOVALUE,
553
notifyCompletion = asn1_NOVALUE,
554
keepActive = asn1_NOVALUE,
557
#'IndAudSignal'{signalName = SignalName,
559
signalRequestID = RID}.
562
ensure_IADMD({_TokenTag, _Line,
563
#'DigitMapDescriptor'{digitMapName = Name,
564
digitMapValue = asn1_NOVALUE}}) ->
565
#'IndAudDigitMapDescriptor'{digitMapName = Name}.
568
merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N,
569
packageVersion = V}) ->
570
#'IndAudPackagesDescriptor'{packageName = N,
574
%% ensure_indAudTerminationStateParm(Token) ->
576
%% {safeToken, _Line, "servicestates"} -> serviceStatesToken;
577
%% {safeToken, _Line, "si"} -> serviceStatesToken;
578
%% {safeToken, _Line, "buffer"} -> bufferToken;
579
%% {safeToken, _Line, "bf"} -> bufferToken;
580
%% PkgdName -> {pkgdName,
581
%% ensure_pkgdName(PkgdName)}
585
%% Types modified by v2:
587
merge_auditDescriptor([]) ->
588
#'AuditDescriptor'{};
589
merge_auditDescriptor(Tokens) when list(Tokens) ->
590
case lists:keysearch(terminationAudit, 1, Tokens) of
591
{value, {terminationAudit, TA}} ->
592
case lists:keydelete(terminationAudit, 1, Tokens) of
594
#'AuditDescriptor'{auditPropertyToken = TA};
596
#'AuditDescriptor'{auditToken = AuditTokens,
597
auditPropertyToken = TA}
600
#'AuditDescriptor'{auditToken = Tokens}
602
merge_auditDescriptor(_) ->
603
#'AuditDescriptor'{}.
610
merge_ServiceChangeParm(Parms) ->
611
Required = [serviceChangeReason, serviceChangeMethod],
612
merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
614
merge_ServiceChangeParm([], SCP, []) ->
617
merge_ServiceChangeParm([], _SCP, Required) ->
618
exit({missing_required_serviceChangeParm, Required});
620
merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
621
when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE,
622
SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
623
SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
624
merge_ServiceChangeParm(Parms, SCP, Req);
625
merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
626
when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
627
MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
628
exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
630
merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
631
when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE,
632
SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
633
SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
634
merge_ServiceChangeParm(Parms, SCP, Req);
635
merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
636
when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
637
Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
638
exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
640
merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
641
when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE ->
642
SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
643
merge_ServiceChangeParm(Parms, SCP, Req);
645
merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
646
when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE ->
647
SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
648
merge_ServiceChangeParm(Parms, SCP, Req);
650
%% REQUIRED (i.e. no default value)
651
merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
652
when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined ->
653
SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
654
Req = lists:delete(serviceChangeReason, Req0),
655
merge_ServiceChangeParm(Parms, SCP, Req);
657
merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
658
when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE ->
659
SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
660
merge_ServiceChangeParm(Parms, SCP, Req);
662
%% REQUIRED (i.e. no default value)
663
merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
664
when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined ->
665
SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
666
Req = lists:delete(serviceChangeMethod, Req0),
667
merge_ServiceChangeParm(Parms, SCP, Req);
669
merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
670
when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE ->
671
SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
672
merge_ServiceChangeParm(Parms, SCP, Req);
674
merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
675
merge_ServiceChangeParm(Parms, SCP0, Req);
677
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
678
when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE, atom(Val) ->
679
SCI = #'AuditDescriptor'{auditToken = [Val]},
680
SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
681
merge_ServiceChangeParm(Parms, SCP, Req);
682
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
683
when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE,tuple(Val) ->
684
SCI = #'AuditDescriptor'{auditPropertyToken = [Val]},
685
SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
686
merge_ServiceChangeParm(Parms, SCP, Req);
687
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
688
when record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor'),
690
SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
691
L = SCI0#'AuditDescriptor'.auditToken,
692
SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]},
693
SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
694
merge_ServiceChangeParm(Parms, SCP, Req);
695
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
696
when record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor'),
698
SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
699
L = SCI0#'AuditDescriptor'.auditPropertyToken,
700
SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]},
701
SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
702
merge_ServiceChangeParm(Parms, SCP, Req);
704
merge_ServiceChangeParm([incomplete|Parms], SCP0, Req)
705
when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag == asn1_NOVALUE ->
706
SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'},
707
merge_ServiceChangeParm(Parms, SCP, Req);
709
merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
713
SCP#'ServiceChangeParm'.serviceChangeAddress;
715
SCP#'ServiceChangeParm'.serviceChangeMgcId;
717
SCP#'ServiceChangeParm'.serviceChangeProfile;
719
SCP#'ServiceChangeParm'.serviceChangeVersion;
721
SCP#'ServiceChangeParm'.serviceChangeReason;
723
SCP#'ServiceChangeParm'.serviceChangeDelay;
725
SCP#'ServiceChangeParm'.serviceChangeMethod;
727
SCP#'ServiceChangeParm'.timeStamp;
729
SCP#'ServiceChangeParm'.serviceChangeInfo
731
exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}});
732
merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) ->
736
SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag
738
exit({at_most_once_serviceChangeParm, {Parm, Parm2}}).
741
merge_ServiceChangeResParm(Parms) ->
742
merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
744
merge_ServiceChangeResParm([], SCRP) ->
746
merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
747
when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE,
748
SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
749
SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
750
merge_ServiceChangeResParm(Parms, SCRP);
751
merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
752
when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
753
MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
754
exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
756
merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
757
when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE,
758
SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
759
SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
760
merge_ServiceChangeResParm(Parms, SCRP);
761
merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
762
when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
763
Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
764
exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
766
merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
767
when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
768
SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
769
merge_ServiceChangeResParm(Parms, SCRP);
771
merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
772
when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
773
SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
774
merge_ServiceChangeResParm(Parms, SCRP);
776
merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
777
when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
778
SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
779
merge_ServiceChangeResParm(Parms, SCRP);
781
merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
784
address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
785
mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
786
profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
787
version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
788
time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
790
exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
793
ensure_serviceChangeMethod({safeToken, _Line, "fl"}) ->
795
ensure_serviceChangeMethod({safeToken, _Line, "failover"}) ->
797
ensure_serviceChangeMethod({safeToken, _Line, "fo"}) ->
799
ensure_serviceChangeMethod({safeToken, _Line, "forced"}) ->
801
ensure_serviceChangeMethod({safeToken, _Line, "gr"}) ->
803
ensure_serviceChangeMethod({safeToken, _Line, "graceful"}) ->
805
ensure_serviceChangeMethod({safeToken, _Line, "rs"}) ->
807
ensure_serviceChangeMethod({safeToken, _Line, "restart"}) ->
809
ensure_serviceChangeMethod({safeToken, _Line, "dc"}) ->
811
ensure_serviceChangeMethod({safeToken, _Line, "disconnected"}) ->
813
ensure_serviceChangeMethod({safeToken, _Line, "ho"}) ->
815
ensure_serviceChangeMethod({safeToken, _Line, "handoff"}) ->
817
ensure_serviceChangeMethod({safeToken, Line, Text}) ->
818
return_error(Line, {bad_serviceChangeMethod, Text}).
821
merge_topologyDescriptor(Components) ->
822
merge_topologyDescriptor(Components, #'TopologyRequest'{}, []).
824
merge_topologyDescriptor([], TR, TRs) ->
825
lists:reverse([ensure_TopologyRequest(TR)|TRs]);
826
merge_topologyDescriptor(
828
#'TopologyRequest'{terminationFrom = undefined} = TR1, TRs) ->
829
%% d("merge_topologyDescriptor(1) -> entry with"
831
%% "~n TR1: ~p", [From, TR1]),
832
TR2 = TR1#'TopologyRequest'{terminationFrom = From},
833
merge_topologyDescriptor(Comps, TR2, TRs);
834
merge_topologyDescriptor(
836
#'TopologyRequest'{terminationTo = undefined} = TR1,
838
%% d("merge_topologyDescriptor(2) -> entry with"
840
%% "~n TR1: ~p", [To, TR1]),
841
TR2 = TR1#'TopologyRequest'{terminationTo = To},
842
merge_topologyDescriptor(Comps, TR2, TRs);
843
merge_topologyDescriptor([{tid, From}|Comps], TR1, TRs) ->
844
%% d("merge_topologyDescriptor(3) -> entry with"
846
%% "~n TR1: ~p", [From, TR1]),
847
TR2 = #'TopologyRequest'{terminationFrom = From},
848
merge_topologyDescriptor(Comps, TR2, [TR1 | TRs]);
849
merge_topologyDescriptor([{direction, Dir}|Comps], TR1, TRs) ->
850
%% d("merge_topologyDescriptor -> entry with"
852
%% "~n TR1: ~p", [Dir, TR1]),
853
TR2 = TR1#'TopologyRequest'{topologyDirection = Dir},
854
merge_topologyDescriptor(Comps, TR2, TRs);
855
merge_topologyDescriptor([{sid, SID}|Comps], TR1, TRs) ->
856
%% d("merge_topologyDescriptor -> entry with"
858
%% "~n TR1: ~p", [SID, TR1]),
859
TR2 = TR1#'TopologyRequest'{streamID = SID},
860
merge_topologyDescriptor(Comps, TR2, TRs);
861
merge_topologyDescriptor(
862
[{direction_ext, EDir}|Comps],
863
#'TopologyRequest'{topologyDirection = asn1_NOVALUE} = TR1, TRs) ->
864
%% d("merge_topologyDescriptor -> entry with"
866
%% "~n TR1: ~p", [EDir, TR1]),
867
TR2 = TR1#'TopologyRequest'{topologyDirection = oneway,
868
topologyDirectionExtension = EDir},
869
merge_topologyDescriptor(Comps, TR2, TRs);
870
merge_topologyDescriptor([{direction_ext, EDir}|Comps], TR1, TRs) ->
871
%% d("merge_topologyDescriptor -> entry with"
873
%% "~n TR1: ~p", [EDir, TR1]),
874
TR2 = TR1#'TopologyRequest'{topologyDirectionExtension = EDir},
875
merge_topologyDescriptor(Comps, TR2, TRs);
876
merge_topologyDescriptor(Comps, TR, TRs) ->
877
%% d("merge_topologyDescriptor -> entry with"
880
%% "~n TRs: ~p", [Comps, TR, TRs]),
881
return_error(0, {bad_topologyDescriptor, Comps, TR, TRs}).
884
%% merge_topologyDescriptor([{tid, From},
887
%% {sid, SID}|Comps], TRs) ->
888
%% d("merge_topologyDescriptor -> entry with"
892
%% "~n SID: ~p", [From, To, Dir, SID]),
893
%% TR = make_TopologyRequest(From, To, Dir, SID),
894
%% merge_topologyDescriptor(Comps, [TR | TRs]);
895
%% merge_topologyDescriptor([{tid, From},
897
%% {direction, Dir}|Comps], TRs) ->
898
%% d("merge_topologyDescriptor -> entry with"
901
%% "~n Dir: ~p", [From, To, Dir]),
902
%% TR = make_TopologyRequest(From, To, Dir),
903
%% merge_topologyDescriptor(Comps, [TR | TRs]);
904
%% merge_topologyDescriptor(Comps, TRs) ->
905
%% d("merge_topologyDescriptor -> entry with"
907
%% "~n TRs: ~p", [Comps, TRs]),
908
%% return_error(0, {bad_topologyDescriptor, Comps, TRs}).
911
ensure_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
913
topologyDirection = Dir} = R)
914
when (From =/= asn1_NOVALUE) and
915
(To =/= asn1_NOVALUE) and
916
(Dir =/= asn1_NOVALUE) ->
918
ensure_TopologyRequest(R) ->
919
return_error(0, {bad_TopologyRequest, R}).
922
%% make_TopologyRequest(From, To, Dir, SID) ->
923
%% TR = #'TopologyRequest'{terminationFrom = From,
924
%% terminationTo = To,
926
%% make_TopologyRequest(TR, Dir).
928
%% make_TopologyRequest(From, To, Dir) ->
929
%% TR = #'TopologyRequest'{terminationFrom = From,
930
%% terminationTo = To},
931
%% make_TopologyRequest(TR, Dir).
933
%% make_TopologyRequest(TR, bothway = Dir) ->
934
%% TR#'TopologyRequest'{topologyDirection = Dir};
935
%% make_TopologyRequest(TR, isolate = Dir) ->
936
%% TR#'TopologyRequest'{topologyDirection = Dir};
937
%% make_TopologyRequest(TR, oneway = Dir) ->
938
%% TR#'TopologyRequest'{topologyDirection = Dir};
939
%% make_TopologyRequest(TR, onewayexternal = Dir) ->
940
%% TR#'TopologyRequest'{topologyDirection = oneway,
941
%% topologyDirectionExtension = Dir};
942
%% make_TopologyRequest(TR, onewayboth = Dir) ->
943
%% TR#'TopologyRequest'{topologyDirection = oneway,
944
%% topologyDirectionExtension = Dir}.
946
ensure_profile({_TokenTag, Line, Text}) ->
947
case string:tokens(Text, [$/]) of
949
Version2 = ensure_version(Version),
950
#'ServiceChangeProfile'{profileName = Name, version = Version2};
952
return_error(Line, {bad_profile, Text})
955
ensure_version(Version) ->
956
ensure_uint(Version, 0, 99).
958
merge_signalRequest(SignalName, PropertyParms) ->
959
%% d("merge_signalRequest -> entry with"
960
%% "~n SignalName: ~p"
961
%% "~n PropertyParms: ~p", [SignalName, PropertyParms]),
962
Sig = #'Signal'{signalName = SignalName},
964
do_merge_signalRequest(Sig, PropertyParms, SPL).
966
do_merge_signalRequest(Sig, [H | T], SPL) ->
967
%% d("do_merge_signalRequest -> entry with"
970
%% "~n SPL: ~p", [Sig, H, SPL]),
972
{stream, SID} when Sig#'Signal'.streamID == asn1_NOVALUE ->
973
do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL);
974
{signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
975
do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
976
{duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
977
do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
978
{notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
979
do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
980
keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE ->
981
do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
983
SP = #'SigParameter'{sigParameterName = Name,
984
value = PP#'PropertyParm'.value,
985
extraInfo = PP#'PropertyParm'.extraInfo},
986
do_merge_signalRequest(Sig, T, [SP | SPL]);
987
{direction, Dir} when Sig#'Signal'.direction == asn1_NOVALUE ->
988
do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL);
989
{requestId, RID} when Sig#'Signal'.requestID == asn1_NOVALUE ->
990
do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL);
991
{intersigDelay, ISD} when Sig#'Signal'.intersigDelay == asn1_NOVALUE ->
992
do_merge_signalRequest(Sig#'Signal'{intersigDelay = ISD}, T, SPL);
994
return_error(0, {bad_sigParm, H})
996
do_merge_signalRequest(Sig, [], SPL) ->
997
Sig#'Signal'{sigParList = lists:reverse(SPL)} .
999
%% eventStream = StreamToken EQUAL StreamID
1000
%% eventOther = eventParameterName parmValue
1001
select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
1002
{stream, ensure_uint16(Value)};
1003
select_stream_or_other("st", Value) ->
1004
{stream, ensure_uint16(Value)};
1005
select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
1006
{stream, ensure_uint16(Value)};
1007
select_stream_or_other("stream", Value) ->
1008
{stream, ensure_uint16(Value)};
1009
select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
1010
EP = #'EventParameter'{eventParameterName = Name,
1014
ensure_eventDM({_TokenTag, Line, DMD})
1015
when record(DMD, 'DigitMapDescriptor') ->
1016
Name = DMD#'DigitMapDescriptor'.digitMapName,
1017
Val = DMD#'DigitMapDescriptor'.digitMapValue,
1019
Name == asn1_NOVALUE, Val /= asn1_NOVALUE ->
1020
{'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
1021
DMV = #'DigitMapValue'{startTimer = Start,
1024
digitMapBody = Body,
1025
durationTimer = Duration},
1026
{eventDM, {digitMapValue, DMV}};
1027
Name /= asn1_NOVALUE, Val == asn1_NOVALUE ->
1028
{eventDM, {digitMapName, Name}};
1030
return_error(Line, {bad_eventDM, DMD})
1033
ensure_DMD({_TokenTag, _Line, DMD})
1034
when record(DMD, 'DigitMapDescriptor') ->
1036
case DMD#'DigitMapDescriptor'.digitMapValue of
1037
%% Note that the values of the digitMapBody and durationTimers
1038
%% are swapped by the scanner (this is done because of a
1039
%% problem in the flex scanner).
1040
#'DigitMapValue'{durationTimer = Body,
1041
digitMapBody = Duration} = DMV ->
1042
%% Convert to version 1 DigitMapValue
1043
DMV#'DigitMapValue'{digitMapBody = Body,
1044
durationTimer = Duration};
1048
DMD#'DigitMapDescriptor'{digitMapValue = Val2}.
1051
merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
1052
StreamId = asn1_NOVALUE,
1054
do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
1056
do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
1057
do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
1058
do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
1059
do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
1060
do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
1061
#'ObservedEvent'{eventName = EventName,
1062
timeNotation = TimeStamp,
1063
streamID = StreamID,
1064
eventParList = lists:reverse(EPL)}.
1066
merge_eventSpec(OE) when record(OE, 'ObservedEvent'),
1067
OE#'ObservedEvent'.timeNotation == asn1_NOVALUE ->
1068
#'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
1069
streamID = OE#'ObservedEvent'.streamID,
1070
eventParList = OE#'ObservedEvent'.eventParList};
1071
merge_eventSpec(OE) ->
1072
return_error(0, {bad_event_spec, OE}).
1074
make_RegulatedEmbeddedDescriptor({embed, SD, SED}) ->
1075
%% d("make_RegulatedEmbeddedDescriptor(embed) -> entry with"
1077
%% "~n SED: ~p", [SD, SED]),
1078
#'RegulatedEmbeddedDescriptor'{secondEvent = SED,
1079
signalsDescriptor = SD}.
1081
merge_eventParameters(Params) ->
1082
%% d("merge_eventParameters -> entry with"
1083
%% "~n Params: ~p", [Params]),
1086
RA = #'RequestedActions'{},
1088
do_merge_eventParameters(Params, SID, EPL, RA, HasA) .
1090
do_merge_eventParameters([H | T], SID, EPL, RA, HasA) ->
1091
%% d("do_merge_eventParameters -> entry with"
1096
%% "~n HasA: ~p", [H, SID, EPL, RA, HasA]),
1098
keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE ->
1099
RA2 = RA#'RequestedActions'{keepActive = true},
1100
do_merge_eventParameters(T, SID, EPL, RA2, yes);
1101
resetEventsDescriptor when RA#'RequestedActions'.resetEventsDescriptor == asn1_NOVALUE ->
1102
RA2 = RA#'RequestedActions'{resetEventsDescriptor = 'NULL'},
1103
do_merge_eventParameters(T, SID, EPL, RA2, yes);
1104
{embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE ->
1105
RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
1107
do_merge_eventParameters(T, SID, EPL, RA2, yes);
1108
{eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE ->
1109
RA2 = RA#'RequestedActions'{eventDM = DM},
1110
do_merge_eventParameters(T, SID, EPL, RA2, yes);
1111
{stream, NewSID} when SID == asn1_NOVALUE ->
1112
do_merge_eventParameters(T, NewSID, EPL, RA, HasA);
1113
{other, PP} when record(PP, 'PropertyParm') ->
1114
EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
1115
value = PP#'PropertyParm'.value,
1116
extraInfo = PP#'PropertyParm'.extraInfo},
1117
do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA);
1118
{other, EP} when record(EP, 'EventParameter') ->
1119
do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA);
1120
{notifyBehaviour, NB} when RA#'RequestedActions'.notifyBehaviour == asn1_NOVALUE ->
1121
RA2 = RA#'RequestedActions'{notifyBehaviour = NB},
1122
do_merge_eventParameters(T, SID, EPL, RA2, yes);
1124
return_error(0, {bad_eventParameter, H})
1126
do_merge_eventParameters([], SID, EPL, RA, yes) ->
1127
#'RequestedEvent'{streamID = SID,
1129
evParList = lists:reverse(EPL)};
1130
do_merge_eventParameters([], SID, EPL, _RA, no) ->
1131
#'RequestedEvent'{streamID = SID,
1132
eventAction = asn1_NOVALUE,
1133
evParList = lists:reverse(EPL)}.
1135
merge_secondEventParameters(Params) ->
1136
%% d("merge_secondEventParameters -> entry with"
1137
%% "~n Params: ~p", [Params]),
1140
SRA = #'SecondRequestedActions'{},
1142
do_merge_secondEventParameters(Params, SID, EPL, SRA, HasA) .
1144
do_merge_secondEventParameters([H | T], SID, EPL, SRA, HasA) ->
1145
%% d("do_merge_secondEventParameters -> entry with"
1150
%% "~n HasA: ~p", [H, SID, EPL, SRA, HasA]),
1152
keepActive when SRA#'SecondRequestedActions'.keepActive == asn1_NOVALUE ->
1153
SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
1154
do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
1155
resetEventsDescriptor when SRA#'SecondRequestedActions'.resetEventsDescriptor == asn1_NOVALUE ->
1156
SRA2 = SRA#'SecondRequestedActions'{resetEventsDescriptor = 'NULL'},
1157
do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
1158
{second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor == asn1_NOVALUE ->
1159
SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
1160
do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
1161
{eventDM, DM} when SRA#'SecondRequestedActions'.eventDM == asn1_NOVALUE ->
1162
SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
1163
do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
1164
{stream, NewSID} when SID == asn1_NOVALUE ->
1165
do_merge_secondEventParameters(T, NewSID, EPL, SRA, HasA);
1166
{other, PP} when record(PP, 'PropertyParm') ->
1167
EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
1168
value = PP#'PropertyParm'.value,
1169
extraInfo = PP#'PropertyParm'.extraInfo},
1170
do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA);
1171
{other, EP} when record(EP, 'EventParameter') ->
1172
do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA);
1173
{notifyBehaviour, NB} when SRA#'SecondRequestedActions'.notifyBehaviour == asn1_NOVALUE ->
1174
SRA2 = SRA#'SecondRequestedActions'{notifyBehaviour = NB},
1175
do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
1177
return_error(0, {bad_secondEventParameter, H})
1179
do_merge_secondEventParameters([], SID, EPL, SRA, yes) ->
1180
#'SecondRequestedEvent'{streamID = SID,
1182
evParList = lists:reverse(EPL)};
1183
do_merge_secondEventParameters([], SID, EPL, _SRA, no) ->
1184
#'SecondRequestedEvent'{streamID = SID,
1185
eventAction = asn1_NOVALUE,
1186
evParList = lists:reverse(EPL)}.
1188
%% terminationID = "ROOT" / pathName / "$" / "*"
1189
%% Total length of pathName must not exceed 64 chars.
1190
%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
1191
%% ["@" pathDomainName ]
1192
%% ABNF allows two or more consecutive "." although it is meaningless
1193
%% in a path domain name.
1194
%% pathDomainName = (ALPHA / DIGIT / "*" )
1195
%% *63(ALPHA / DIGIT / "-" / "*" / ".")
1196
ensure_terminationID({safeToken, _Line, LowerText}) ->
1197
%% terminationID = "ROOT" / pathName / "$" / "*"
1198
decode_term_id(LowerText, false, [], []).
1200
decode_term_id([H | T], Wild, Id, Component) ->
1202
$/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
1203
$* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
1204
$$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
1205
_ -> decode_term_id(T, Wild, Id, [H | Component])
1207
decode_term_id([], Wild, Id, Component) ->
1208
Id2 = [lists:reverse(Component) | Id],
1209
#megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
1211
ensure_pathName({_TokenTag, _Line, Text}) ->
1212
Text. %% BUGBUG: ensure values
1214
%% TimeStamp = Date "T" Time ; per ISO 8601:1988
1215
%% Date = 8(DIGIT) ; Date = yyyymmdd
1216
%% Time = 8(DIGIT) ; Time = hhmmssss
1217
ensure_timeStamp({'TimeStampToken', Line, Text}) ->
1218
case string:tokens(Text, [$T, $t]) of
1220
#'TimeNotation'{date = Date, time = Time};
1222
return_error(Line, {bad_timeStamp, Text})
1225
ensure_transactionID(TransId) ->
1226
ensure_uint32(TransId).
1228
%% transactionAck = transactionID / (transactionID "-" transactionID)
1229
ensure_transactionAck({safeToken, _Line, Text}) ->
1230
case string:tokens(Text, [$-]) of
1232
#'TransactionAck'{firstAck = ensure_transactionID(Id)};
1234
#'TransactionAck'{firstAck = ensure_transactionID(Id),
1235
lastAck = ensure_transactionID(Id2)}
1238
merge_context_request(asn1_NOVALUE, Prop) ->
1239
merge_context_request(#'ContextRequest'{}, Prop);
1241
merge_context_request(#'ContextRequest'{priority = asn1_NOVALUE} = CR,
1243
CR#'ContextRequest'{priority = Int};
1245
merge_context_request(#'ContextRequest'{emergency = asn1_NOVALUE} = CR,
1246
{emergency, Bool}) ->
1247
CR#'ContextRequest'{emergency = Bool};
1249
merge_context_request(#'ContextRequest'{topologyReq = asn1_NOVALUE} = CR,
1250
{topology, Desc}) ->
1251
CR#'ContextRequest'{topologyReq = Desc};
1253
merge_context_request(#'ContextRequest'{iepscallind = asn1_NOVALUE} = CR,
1254
{iepsCallind, Ind}) ->
1255
CR#'ContextRequest'{iepscallind = Ind};
1257
merge_context_request(#'ContextRequest'{contextProp = asn1_NOVALUE} = CR,
1258
{contextProp, Props}) ->
1259
CR#'ContextRequest'{contextProp = Props};
1261
merge_context_request(#'ContextRequest'{contextList = asn1_NOVALUE} = CR,
1262
{contextList, IDs}) ->
1263
CR#'ContextRequest'{contextList = IDs};
1265
merge_context_request(CR, {Tag, Val}) ->
1268
priority -> CR#'ContextRequest'.priority;
1269
emergency -> CR#'ContextRequest'.emergency;
1270
topology -> CR#'ContextRequest'.topologyReq;
1271
iepsCallind -> CR#'ContextRequest'.iepscallind;
1272
contextProp -> CR#'ContextRequest'.contextProp;
1273
contextList -> CR#'ContextRequest'.contextList
1275
exit({at_most_once_contextProperty, {Tag, Val, Val2}}).
1278
merge_context_attr_audit_request(
1279
#'ContextAttrAuditRequest'{contextPropAud = asn1_NOVALUE} = CAAR, []) ->
1282
merge_context_attr_audit_request(
1283
#'ContextAttrAuditRequest'{contextPropAud = CPA} = CAAR, []) ->
1285
CAAR#'ContextAttrAuditRequest'{contextPropAud = lists:reverse(CPA)};
1286
merge_context_attr_audit_request(CAAR, [H|T]) ->
1288
priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
1289
CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'},
1290
merge_context_attr_audit_request(CAAR2, T);
1292
emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
1293
CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'},
1294
merge_context_attr_audit_request(CAAR2, T);
1296
topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
1297
CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'},
1298
merge_context_attr_audit_request(CAAR2, T);
1300
iepsCallind when CAAR#'ContextAttrAuditRequest'.iepscallind == asn1_NOVALUE ->
1301
CAAR2 = CAAR#'ContextAttrAuditRequest'{iepscallind = 'NULL'},
1302
merge_context_attr_audit_request(CAAR2, T);
1304
{prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud == asn1_NOVALUE ->
1305
CPA = [#'IndAudPropertyParm'{name = Name}],
1306
CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA},
1307
merge_context_attr_audit_request(CAAR2, T);
1310
CPA = CAAR#'ContextAttrAuditRequest'.contextPropAud,
1311
CPA2 = [#'IndAudPropertyParm'{name = Name}|CPA],
1312
CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2},
1313
merge_context_attr_audit_request(CAAR2, T);
1315
{select_prio, Prio} when CAAR#'ContextAttrAuditRequest'.selectpriority == asn1_NOVALUE ->
1316
CAAR2 = CAAR#'ContextAttrAuditRequest'{selectpriority = Prio},
1317
merge_context_attr_audit_request(CAAR2, T);
1319
{select_emergency, EV} when CAAR#'ContextAttrAuditRequest'.selectemergency == asn1_NOVALUE ->
1320
CAAR2 = CAAR#'ContextAttrAuditRequest'{selectemergency = EV},
1321
merge_context_attr_audit_request(CAAR2, T);
1323
{select_ieps, IV} when CAAR#'ContextAttrAuditRequest'.selectiepscallind == asn1_NOVALUE ->
1324
CAAR2 = CAAR#'ContextAttrAuditRequest'{selectiepscallind = IV},
1325
merge_context_attr_audit_request(CAAR2, T);
1327
{select_logic, SL} when CAAR#'ContextAttrAuditRequest'.selectLogic == asn1_NOVALUE ->
1328
CAAR2 = CAAR#'ContextAttrAuditRequest'{selectLogic = SL},
1329
merge_context_attr_audit_request(CAAR2, T);
1331
%% BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
1333
%% For some strange reason, contextAttrDescriptor was added
1334
%% to contextAuditSelector. But there is no place for this
1335
%% info in the ContextAttrAuditRequest. Since contextAttrDescriptor
1336
%% can also be found in contextProperty (which correspond to
1337
%% ContextRequest), the question is if this info should go there
1338
%% or if we shall just drop it. For now we drop it.
1340
{contextProp, _PPs} ->
1341
merge_context_attr_audit_request(CAAR, T);
1343
{contextList, _IDs} ->
1344
merge_context_attr_audit_request(CAAR, T);
1347
exit({unexpected_contextAttrAudit_item, H})
1351
merge_action_request(CtxId, Items) ->
1352
do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId).
1354
do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
1356
{commandRequest, CmdReq} ->
1357
do_merge_action_request(T, [CmdReq|CmdReqs],
1358
CtxReq, CtxAuditReq, CtxId);
1360
{contextProp, ContextProp} ->
1361
do_merge_action_request(T, CmdReqs,
1362
merge_context_request(CtxReq, ContextProp),
1363
CtxAuditReq, CtxId);
1365
{contextAudit, ContextAuditReq} when CtxAuditReq == asn1_NOVALUE ->
1366
do_merge_action_request(T, CmdReqs,
1367
CtxReq, ContextAuditReq, CtxId)
1369
do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
1370
#'ActionRequest'{contextId = CtxId,
1371
contextRequest = strip_ContextRequest(CtxReq),
1372
contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq),
1373
commandRequests = lists:reverse(CmdReqs)}.
1377
%% In order to solve a problem in the parser, the error descriptor
1378
%% has been put last in the non-empty commandReplyList, if it is not
1380
merge_action_reply(Items) ->
1381
do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []).
1383
do_merge_action_reply([], Err, Ctx, Cmds) ->
1384
#'ActionReply'{errorDescriptor = Err,
1385
contextReply = strip_ContextRequest(Ctx),
1386
commandReply = lists:reverse(Cmds)};
1387
do_merge_action_reply([H|T], Err0, CR, Cmds) ->
1389
{error, Err1} when Err0 == asn1_NOVALUE ->
1390
do_merge_action_reply(T, Err1, CR, Cmds);
1392
do_merge_action_reply(T, Err0, CR, [Cmd | Cmds]);
1393
{context, CtxProp} ->
1394
do_merge_action_reply(T, Err0,
1395
merge_context_request(CR, CtxProp), Cmds)
1398
merge_auditOther([TID], TAR) ->
1400
#'AuditResult'{terminationID = TID,
1401
terminationAuditResult = TAR}};
1402
merge_auditOther(TIDs, TAR) ->
1403
{auditResultTermList,
1404
#'TermListAuditResult'{terminationIDList = TIDs,
1405
terminationAuditResult = TAR}}.
1407
strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
1408
emergency = asn1_NOVALUE,
1409
topologyReq = asn1_NOVALUE,
1410
iepscallind = asn1_NOVALUE,
1411
contextProp = asn1_NOVALUE,
1412
contextList = asn1_NOVALUE}) ->
1414
strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
1415
emergency = asn1_NOVALUE,
1416
topologyReq = asn1_NOVALUE,
1417
iepscallind = asn1_NOVALUE,
1419
contextList = asn1_NOVALUE}) ->
1421
%% strip_ContextRequest(asn1_NOVALUE) ->
1423
strip_ContextRequest(R) ->
1426
strip_ContextAttrAuditRequest(
1427
#'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
1428
emergency = asn1_NOVALUE,
1429
topology = asn1_NOVALUE,
1430
iepscallind = asn1_NOVALUE,
1431
contextPropAud = asn1_NOVALUE,
1432
selectpriority = asn1_NOVALUE,
1433
selectemergency = asn1_NOVALUE,
1434
selectiepscallind = asn1_NOVALUE,
1435
selectLogic = asn1_NOVALUE}) ->
1437
strip_ContextAttrAuditRequest(
1438
#'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
1439
emergency = asn1_NOVALUE,
1440
topology = asn1_NOVALUE,
1441
iepscallind = asn1_NOVALUE,
1442
contextPropAud = [],
1443
selectpriority = asn1_NOVALUE,
1444
selectemergency = asn1_NOVALUE,
1445
selectiepscallind = asn1_NOVALUE,
1446
selectLogic = asn1_NOVALUE}) ->
1448
strip_ContextAttrAuditRequest(R) ->
1451
merge_AmmRequest_descriptors([], Acc) ->
1453
merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) ->
1454
merge_AmmRequest_descriptors(Descs, Acc);
1455
merge_AmmRequest_descriptors([Desc|Descs], Acc) ->
1456
merge_AmmRequest_descriptors(Descs, [Desc|Acc]).
1458
make_auditRequest([TID], AD) ->
1459
#'AuditRequest'{terminationID = TID,
1460
auditDescriptor = AD};
1461
make_auditRequest([TID|_] = TIDList, AD) ->
1462
#'AuditRequest'{terminationID = TID,
1463
auditDescriptor = AD,
1464
terminationIDList = TIDList}.
1466
make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
1467
Req = #'CommandRequest'{command = {CmdTag, Cmd}},
1470
Req#'CommandRequest'{wildcardReturn = 'NULL'};
1471
[$o, $-, $w, $- | _] ->
1472
Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
1474
Req#'CommandRequest'{optional = 'NULL'};
1479
merge_terminationAudit(AuditReturnParameters) ->
1480
lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
1482
do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
1484
{auditReturnItem, AuditItem} ->
1485
do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
1486
AuditReturnParameter ->
1487
do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
1489
do_merge_terminationAudit([], AuditReturnParameters, []) ->
1490
AuditReturnParameters;
1491
do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
1492
AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
1493
AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
1494
[AuditReturnParameter | AuditReturnParameters].
1496
merge_mediaDescriptor(MediaParms) ->
1497
do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
1499
do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
1501
{streamParm, Parm} when Multi == [] ->
1502
do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
1503
{streamDescriptor, Desc} when One == [] ->
1504
do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
1505
{termState, TS2} when TS == asn1_NOVALUE ->
1506
do_merge_mediaDescriptor(T, TS2, One, Multi);
1508
return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
1510
do_merge_mediaDescriptor([], TS, One, Multi) ->
1512
One == [], Multi == [] ->
1513
#'MediaDescriptor'{streams = asn1_NOVALUE,
1514
termStateDescr = TS};
1515
One /= [], Multi == [] ->
1516
#'MediaDescriptor'{streams = {oneStream, merge_streamParms(One)},
1517
termStateDescr = TS};
1518
One == [], Multi /= [] ->
1519
#'MediaDescriptor'{streams = {multiStream, lists:reverse(Multi)},
1520
termStateDescr = TS}
1523
merge_streamParms(TaggedStreamParms) ->
1524
SP = #'StreamParms'{},
1525
do_merge_streamParms(TaggedStreamParms, SP).
1527
do_merge_streamParms([{Tag, D} | T] = All, SP) ->
1529
local when SP#'StreamParms'.localDescriptor == asn1_NOVALUE ->
1530
do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
1531
remote when SP#'StreamParms'.remoteDescriptor == asn1_NOVALUE ->
1532
do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
1535
case SP#'StreamParms'.localControlDescriptor of
1537
#'LocalControlDescriptor'{propertyParms = []};
1541
LCD2 = do_merge_control_streamParms(D, LCD),
1542
do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
1543
statistics when SP#'StreamParms'.statisticsDescriptor == asn1_NOVALUE ->
1544
do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D});
1546
return_error(0, {do_merge_streamParms, [All, SP]})
1548
do_merge_streamParms([], SP) when record(SP#'StreamParms'.localControlDescriptor, 'LocalControlDescriptor') ->
1549
LCD = SP#'StreamParms'.localControlDescriptor,
1550
PP = LCD#'LocalControlDescriptor'.propertyParms,
1551
LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
1552
SP#'StreamParms'{localControlDescriptor = LCD2};
1553
do_merge_streamParms([], SP) ->
1557
do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
1559
group when LCD#'LocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
1560
LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
1561
do_merge_control_streamParms(T, LCD2);
1562
value when LCD#'LocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
1563
LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
1564
do_merge_control_streamParms(T, LCD2);
1565
mode when LCD#'LocalControlDescriptor'.streamMode == asn1_NOVALUE ->
1566
LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
1567
do_merge_control_streamParms(T, LCD2);
1569
PP = LCD#'LocalControlDescriptor'.propertyParms,
1570
LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
1571
do_merge_control_streamParms(T, LCD2);
1573
return_error(0, {do_merge_control_streamParms, [All, LCD]})
1575
do_merge_control_streamParms([], LCD) ->
1578
merge_terminationStateDescriptor(Parms) ->
1579
TSD = #'TerminationStateDescriptor'{propertyParms = []},
1580
do_merge_terminationStateDescriptor(Parms, TSD).
1582
do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
1584
serviceState when TSD#'TerminationStateDescriptor'.serviceState == asn1_NOVALUE ->
1585
TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
1586
do_merge_terminationStateDescriptor(T, TSD2);
1587
eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl == asn1_NOVALUE->
1588
TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
1589
do_merge_terminationStateDescriptor(T, TSD2);
1591
PP = TSD#'TerminationStateDescriptor'.propertyParms,
1592
TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
1593
do_merge_terminationStateDescriptor(T, TSD2)
1595
do_merge_terminationStateDescriptor([], TSD) ->
1596
PP = TSD#'TerminationStateDescriptor'.propertyParms,
1597
TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
1599
ensure_prop_groups({_TokenTag, _Line, Text}) ->
1602
parse_prop_name(Text, Group, Groups).
1604
parse_prop_name([Char | Rest] = All, Group, Groups) ->
1605
case ?classify_char(Char) of
1607
parse_prop_name(Rest, Group, Groups);
1609
parse_prop_name(Rest, Group, Groups);
1612
do_parse_prop_name(All, Name, Group, Groups)
1614
parse_prop_name([] = All, Group, Groups) ->
1616
do_parse_prop_name(All, Name, Group, Groups).
1618
do_parse_prop_name([Char | Rest], Name, Group, Groups) ->
1619
case ?classify_char(Char) of
1621
do_parse_prop_name(Rest, [Char | Name], Group, Groups);
1622
rest_char when Char == $=, Name /= [] ->
1623
%% Now we have a complete name
1625
Name == "v", Group /= [] ->
1626
%% v= is a property group delimiter,
1627
%% lets create yet another property group.
1628
Groups2 = [lists:reverse(Group) | Groups],
1630
parse_prop_value(Rest, Name, Group2, Groups2);
1632
%% Use current property group
1633
parse_prop_value(Rest, Name, Group, Groups)
1636
return_error(0, {bad_prop_name, lists:reverse(Name), Char})
1638
do_parse_prop_name([], [], [], Groups) ->
1639
lists:reverse(Groups);
1640
do_parse_prop_name([], [], Group, Groups) ->
1641
Group2 = lists:reverse(Group),
1642
lists:reverse([Group2 | Groups]);
1643
do_parse_prop_name([], Name, Group, Groups) when Name /= [] ->
1644
%% Assume end of line
1646
PP = make_prop_parm(Name, Value),
1647
Group2 = lists:reverse([PP | Group]),
1648
lists:reverse([Group2 | Groups]).
1650
parse_prop_value(Chars, Name, Group, Groups) ->
1652
do_parse_prop_value(Chars, Name, Value, Group, Groups).
1654
do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) ->
1655
case ?classify_char(Char) of
1657
%% Now we have a complete "name=value" pair
1658
PP = make_prop_parm(Name, Value),
1659
parse_prop_name(Rest, [PP | Group], Groups);
1661
do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups)
1663
do_parse_prop_value([], Name, Value, Group, Groups) ->
1664
%% Assume end of line
1665
PP = make_prop_parm(Name, Value),
1666
Group2 = lists:reverse([PP | Group]),
1667
lists:reverse([Group2 | Groups]).
1669
make_prop_parm(Name, Value) ->
1670
#'PropertyParm'{name = lists:reverse(Name),
1671
value = [lists:reverse(Value)]}.
1673
ensure_uint({_TokenTag, Line, Val}, Min, Max) when integer(Val) ->
1675
integer(Min), Val >= Min ->
1677
integer(Max), Val =< Max ->
1682
return_error(Line, {too_large_integer, Val, Max})
1685
return_error(Line, {too_small_integer, Val, Min})
1687
ensure_uint({TokenTag, Line, Text}, Min, Max) ->
1688
case catch list_to_integer(Text) of
1690
return_error(Line, {not_an_integer, Text});
1691
Val when integer(Val) ->
1692
ensure_uint({TokenTag, Line, Val}, Min, Max)
1694
ensure_uint(Val, Min, Max) ->
1695
ensure_uint({uint, 0, Val}, Min, Max).
1697
ensure_uint16(Int) ->
1698
ensure_uint(Int, 0, 65535).
1700
ensure_uint32(Int) ->
1701
ensure_uint(Int, 0, 4294967295) .
1704
ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
1705
ensure_uint(length(Chars), Min, Max),
1706
hex_to_int(Chars, []);
1707
ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
1708
ensure_uint(length(Chars), Min, Max),
1709
hex_to_int(Chars, []);
1710
ensure_hex([$0, $x |Chars], Min, Max) ->
1711
ensure_uint(length(Chars), Min, Max),
1712
hex_to_int(Chars, []);
1713
ensure_hex([$0, $X |Chars], Min, Max) ->
1714
ensure_uint(length(Chars), Min, Max),
1715
hex_to_int(Chars, []).
1718
hex_to_int([], Acc) ->
1720
hex_to_int([Char1,Char2|Tail], Acc) ->
1721
Int1 = hchar_to_int(Char1),
1722
Int2 = hchar_to_int(Char2),
1723
Val = Int2 bor (Int1 bsl 4),
1724
hex_to_int(Tail, [Val| Acc]);
1725
hex_to_int([Char], Acc) ->
1726
Int = hchar_to_int(Char),
1727
lists:reverse([Int|Acc]).
1729
hchar_to_int(Char) when $0 =< Char, Char =< $9 ->
1731
hchar_to_int(Char) when $A =< Char, Char =< $F ->
1732
Char - $A + 10; % OTP-4710
1733
hchar_to_int(Char) when $a =< Char, Char =< $f ->
1734
Char - $a + 10. % OTP-4710
1736
value_of({_TokenTag, _Line, Text}) ->
1740
%% -------------------------------------------------------------------
1745
%% %% d(true, F, A).
1746
%% d(get(dbg), F, A).
1749
%% io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]);