1 /******************************************************************************
2 * Copyright (c) 2000-2016 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
20 * Szabo, Janos Zoltan – initial implementation
24 ******************************************************************************/
28 #include "../common/memory.h"
29 #include "Parameters.h"
30 #include "Param_Types.hh"
37 #include "Charstring.hh"
38 #include "XmlReader.hh"
40 static const Token_Match
boolean_true_match("^(true).*$",TRUE
);
41 static const Token_Match
boolean_false_match("^(false).*$",TRUE
);
48 BOOLEAN::BOOLEAN(boolean other_value
)
51 boolean_value
= other_value
;
54 BOOLEAN::BOOLEAN(const BOOLEAN
& other_value
)
55 : Base_Type(other_value
)
57 other_value
.must_bound("Copying an unbound boolean value.");
59 boolean_value
= other_value
.boolean_value
;
62 BOOLEAN
& BOOLEAN::operator=(boolean other_value
)
65 boolean_value
= other_value
;
69 BOOLEAN
& BOOLEAN::operator=(const BOOLEAN
& other_value
)
71 other_value
.must_bound("Assignment of an unbound boolean value.");
73 boolean_value
= other_value
.boolean_value
;
77 boolean
BOOLEAN::operator!() const
79 must_bound("The operand of not operator is an unbound boolean value.");
80 return !boolean_value
;
83 boolean
BOOLEAN::operator&&(boolean other_value
) const
85 must_bound("The left operand of and operator is an unbound boolean value.");
86 return boolean_value
&& other_value
;
89 boolean
BOOLEAN::operator&&(const BOOLEAN
& other_value
) const
91 must_bound("The left operand of and operator is an unbound boolean value.");
92 if (!boolean_value
) return FALSE
;
93 other_value
.must_bound("The right operand of and operator is an unbound "
95 return other_value
.boolean_value
;
98 boolean
BOOLEAN::operator^(boolean other_value
) const
100 must_bound("The left operand of xor operator is an unbound boolean value.");
101 return boolean_value
!= other_value
;
104 boolean
BOOLEAN::operator^(const BOOLEAN
& other_value
) const
106 must_bound("The left operand of xor operator is an unbound boolean value.");
107 other_value
.must_bound("The right operand of xor operator is an unbound "
109 return boolean_value
!= other_value
.boolean_value
;
112 boolean
BOOLEAN::operator||(boolean other_value
) const
114 must_bound("The left operand of or operator is an unbound boolean value.");
115 return boolean_value
|| other_value
;
118 boolean
BOOLEAN::operator||(const BOOLEAN
& other_value
) const
120 must_bound("The left operand of or operator is an unbound boolean value.");
121 if (boolean_value
) return TRUE
;
122 other_value
.must_bound("The right operand of or operator is an unbound "
124 return other_value
.boolean_value
;
127 boolean
BOOLEAN::operator==(boolean other_value
) const
129 must_bound("The left operand of comparison is an unbound boolean value.");
130 return boolean_value
== other_value
;
133 boolean
BOOLEAN::operator==(const BOOLEAN
& other_value
) const
135 must_bound("The left operand of comparison is an unbound boolean value.");
136 other_value
.must_bound("The right operand of comparison is an unbound "
138 return boolean_value
== other_value
.boolean_value
;
141 BOOLEAN::operator boolean() const
143 must_bound("Using the value of an unbound boolean variable.");
144 return boolean_value
;
147 void BOOLEAN::clean_up()
152 void BOOLEAN::log() const
154 if (bound_flag
) TTCN_Logger::log_event_str(boolean_value
? "true" : "false");
155 else TTCN_Logger::log_event_unbound();
158 void BOOLEAN::encode_text(Text_Buf
& text_buf
) const
160 must_bound("Text encoder: Encoding an unbound boolean value.");
161 text_buf
.push_int(boolean_value
? 1 : 0);
164 void BOOLEAN::decode_text(Text_Buf
& text_buf
)
166 int int_value
= text_buf
.pull_int().get_val();
169 boolean_value
= FALSE
;
172 boolean_value
= TRUE
;
175 TTCN_error("Text decoder: An invalid boolean value (%d) was received.",
181 void BOOLEAN::set_param(Module_Param
& param
) {
182 param
.basic_check(Module_Param::BC_VALUE
, "boolean value");
183 Module_Param_Ptr mp
= ¶m
;
184 if (param
.get_type() == Module_Param::MP_Reference
) {
185 mp
= param
.get_referenced_param();
187 if (mp
->get_type()!=Module_Param::MP_Boolean
) param
.type_error("boolean value");
189 boolean_value
= mp
->get_boolean();
192 Module_Param
* BOOLEAN::get_param(Module_Param_Name
& /* param_name */) const
195 return new Module_Param_Unbound();
197 return new Module_Param_Boolean(boolean_value
);
200 void BOOLEAN::encode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& p_buf
,
201 TTCN_EncDec::coding_t p_coding
, ...) const
204 va_start(pvar
, p_coding
);
206 case TTCN_EncDec::CT_BER
: {
207 TTCN_EncDec_ErrorContext
ec("While BER-encoding type '%s': ", p_td
.name
);
208 unsigned BER_coding
=va_arg(pvar
, unsigned);
209 BER_encode_chk_coding(BER_coding
);
210 ASN_BER_TLV_t
*tlv
=BER_encode_TLV(p_td
, BER_coding
);
211 tlv
->put_in_buffer(p_buf
);
212 ASN_BER_TLV_t::destruct(tlv
);
214 case TTCN_EncDec::CT_RAW
: {
215 TTCN_EncDec_ErrorContext
ec("While RAW-encoding type '%s': ", p_td
.name
);
217 TTCN_EncDec_ErrorContext::error_internal
218 ("No RAW descriptor available for type '%s'.", p_td
.name
);
222 RAW_enc_tree
root(TRUE
,NULL
,&rp
,1,p_td
.raw
);
223 RAW_encode(p_td
, root
);
224 root
.put_to_buf(p_buf
);
226 case TTCN_EncDec::CT_TEXT
: {
227 TTCN_EncDec_ErrorContext
ec("While TEXT-encoding type '%s': ", p_td
.name
);
229 TTCN_EncDec_ErrorContext::error_internal
230 ("No TEXT descriptor available for type '%s'.", p_td
.name
);
231 TEXT_encode(p_td
,p_buf
);
233 case TTCN_EncDec::CT_XER
: {
234 TTCN_EncDec_ErrorContext
ec("While XER-encoding type '%s': ", p_td
.name
);
235 unsigned XER_coding
=va_arg(pvar
, unsigned);
236 XER_encode(*p_td
.xer
, p_buf
, XER_coding
, 0, 0);
238 case TTCN_EncDec::CT_JSON
: {
239 TTCN_EncDec_ErrorContext
ec("While JSON-encoding type '%s': ", p_td
.name
);
241 TTCN_EncDec_ErrorContext::error_internal
242 ("No JSON descriptor available for type '%s'.", p_td
.name
);
243 JSON_Tokenizer
tok(va_arg(pvar
, int) != 0);
244 JSON_encode(p_td
, tok
);
245 p_buf
.put_s(tok
.get_buffer_length(), (const unsigned char*)tok
.get_buffer());
248 TTCN_error("Unknown coding method requested to encode type '%s'",
254 void BOOLEAN::decode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& p_buf
,
255 TTCN_EncDec::coding_t p_coding
, ...)
258 va_start(pvar
, p_coding
);
260 case TTCN_EncDec::CT_BER
: {
261 TTCN_EncDec_ErrorContext
ec("While BER-decoding type '%s': ", p_td
.name
);
262 unsigned L_form
=va_arg(pvar
, unsigned);
264 BER_decode_str2TLV(p_buf
, tlv
, L_form
);
265 BER_decode_TLV(p_td
, tlv
, L_form
);
266 if(tlv
.isComplete
) p_buf
.increase_pos(tlv
.get_len());
268 case TTCN_EncDec::CT_RAW
: {
269 TTCN_EncDec_ErrorContext
ec("While RAW-decoding type '%s': ", p_td
.name
);
271 TTCN_EncDec_ErrorContext::error_internal
272 ("No RAW descriptor available for type '%s'.", p_td
.name
);
274 switch(p_td
.raw
->top_bit_order
){
282 if(RAW_decode(p_td
, p_buf
, p_buf
.get_len()*8, order
)<0)
283 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
284 "Can not decode type '%s', because invalid or incomplete"
285 " message was received"
288 case TTCN_EncDec::CT_TEXT
: {
289 Limit_Token_List limit
;
290 TTCN_EncDec_ErrorContext
ec("While TEXT-decoding type '%s': ", p_td
.name
);
292 TTCN_EncDec_ErrorContext::error_internal
293 ("No TEXT descriptor available for type '%s'.", p_td
.name
);
294 const unsigned char *b
=p_buf
.get_data();
295 if(b
[p_buf
.get_len()-1]!='\0'){
296 p_buf
.set_pos(p_buf
.get_len());
297 p_buf
.put_zero(8,ORDER_LSB
);
300 if(TEXT_decode(p_td
,p_buf
,limit
)<0)
301 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
302 "Can not decode type '%s', because invalid or incomplete"
303 " message was received"
306 case TTCN_EncDec::CT_XER
: {
307 TTCN_EncDec_ErrorContext
ec("While XER-decoding type '%s': ", p_td
.name
);
308 unsigned XER_coding
=va_arg(pvar
, unsigned);
309 XmlReaderWrap
reader(p_buf
);
310 for (int success
= reader
.Read(); success
==1; success
=reader
.Read()) {
311 int type
= reader
.NodeType();
312 if (type
==XML_READER_TYPE_ELEMENT
)
315 XER_decode(*p_td
.xer
, reader
, XER_coding
, XER_NONE
, 0);
316 size_t bytes
= reader
.ByteConsumed();
317 p_buf
.set_pos(bytes
);
319 case TTCN_EncDec::CT_JSON
: {
320 TTCN_EncDec_ErrorContext
ec("While JSON-decoding type '%s': ", p_td
.name
);
322 TTCN_EncDec_ErrorContext::error_internal
323 ("No JSON descriptor available for type '%s'.", p_td
.name
);
324 JSON_Tokenizer
tok((const char*)p_buf
.get_data(), p_buf
.get_len());
325 if(JSON_decode(p_td
, tok
, false)<0)
326 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
327 "Can not decode type '%s', because invalid or incomplete"
328 " message was received"
330 p_buf
.set_pos(tok
.get_buf_pos());
333 TTCN_error("Unknown coding method requested to decode type '%s'",
340 BOOLEAN::BER_encode_TLV(const TTCN_Typedescriptor_t
& p_td
,
341 unsigned p_coding
) const
344 ASN_BER_TLV_t
*new_tlv
=BER_encode_chk_bound(is_bound());
346 new_tlv
=ASN_BER_TLV_t::construct(1, NULL
);
347 new_tlv
->V
.str
.Vstr
[0]=boolean_value
==TRUE
?0xFF:0x00;
349 new_tlv
=ASN_BER_V2TLV(new_tlv
, p_td
, p_coding
);
353 boolean
BOOLEAN::BER_decode_TLV(const TTCN_Typedescriptor_t
& p_td
,
354 const ASN_BER_TLV_t
& p_tlv
,
359 ASN_BER_TLV_t stripped_tlv
;
360 BER_decode_strip_tags(*p_td
.ber
, p_tlv
, L_form
, stripped_tlv
);
361 TTCN_EncDec_ErrorContext
ec("While decoding BOOLEAN type: ");
362 stripped_tlv
.chk_constructed_flag(FALSE
);
363 if (!stripped_tlv
.isComplete
) return FALSE
;
364 if(stripped_tlv
.V
.str
.Vlen
!=1)
365 ec
.error(TTCN_EncDec::ET_INVAL_MSG
,
366 "Length of V-part is %lu (instead of 1).",
367 (unsigned long) stripped_tlv
.V
.str
.Vlen
);
368 if(stripped_tlv
.V
.str
.Vlen
>=1) {
369 switch(stripped_tlv
.V
.str
.Vstr
[0]) {
384 int BOOLEAN::TEXT_decode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& buff
,
385 Limit_Token_List
&, boolean no_err
, boolean
/*first_call*/)
388 int decoded_length
= 0;
390 if (p_td
.text
->begin_decode
) {
392 if ((tl
= p_td
.text
->begin_decode
->match_begin(buff
)) < 0) {
393 if (no_err
) return -1;
394 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR
,
395 "The specified token '%s' not found for '%s': ",
396 (const char*) *(p_td
.text
->begin_decode
), p_td
.name
);
399 decoded_length
+= tl
;
400 buff
.increase_pos(tl
);
402 if (buff
.get_read_len() < 1 && no_err
) return -TTCN_EncDec::ET_LEN_ERR
;
404 boolean found
= FALSE
;
406 if ( p_td
.text
->val
.bool_values
407 && p_td
.text
->val
.bool_values
->true_decode_token
) {
409 if ((tl
= p_td
.text
->val
.bool_values
->true_decode_token
->match_begin(buff
)) > -1) {
412 boolean_value
= TRUE
;
417 if ((tl
= boolean_true_match
.match_begin(buff
)) >= 0) {
420 boolean_value
= TRUE
;
425 if ( p_td
.text
->val
.bool_values
426 && p_td
.text
->val
.bool_values
->false_decode_token
) {
428 if ((tl
= p_td
.text
->val
.bool_values
->false_decode_token
->match_begin(buff
)) > -1) {
431 boolean_value
= FALSE
;
436 if ((tl
= boolean_false_match
.match_begin(buff
)) >= 0) {
439 boolean_value
= FALSE
;
445 decoded_length
+= str_len
;
446 buff
.increase_pos(str_len
);
449 if (no_err
) return -1;
450 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR
,
451 "No boolean token found for '%s': ", p_td
.name
);
452 return decoded_length
;
455 if (p_td
.text
->end_decode
) {
457 if ((tl
= p_td
.text
->end_decode
->match_begin(buff
)) < 0) {
458 if (no_err
) return -1;
459 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR
,
460 "The specified token '%s' not found for '%s': ",
461 (const char*) *(p_td
.text
->end_decode
), p_td
.name
);
464 decoded_length
+= tl
;
465 buff
.increase_pos(tl
);
468 return decoded_length
;
472 int BOOLEAN::TEXT_encode(const TTCN_Typedescriptor_t
& p_td
,
473 TTCN_Buffer
& buff
) const{
474 int encoded_length
=0;
475 if(p_td
.text
->begin_encode
){
476 buff
.put_cs(*p_td
.text
->begin_encode
);
477 encoded_length
+=p_td
.text
->begin_encode
->lengthof();
480 TTCN_EncDec_ErrorContext::error
481 (TTCN_EncDec::ET_UNBOUND
, "Encoding an unbound value.");
482 if(p_td
.text
->end_encode
){
483 buff
.put_cs(*p_td
.text
->end_encode
);
484 encoded_length
+=p_td
.text
->end_encode
->lengthof();
486 return encoded_length
;
489 if(p_td
.text
->val
.bool_values
==NULL
){
491 buff
.put_s(4,(const unsigned char*)"true");
495 buff
.put_s(5,(const unsigned char*)"false");
500 if(p_td
.text
->val
.bool_values
->true_encode_token
){
501 buff
.put_cs(*p_td
.text
->val
.bool_values
->true_encode_token
);
502 encoded_length
+=p_td
.text
->
503 val
.bool_values
->true_encode_token
->lengthof();
505 buff
.put_s(4,(const unsigned char*)"true");
510 if(p_td
.text
->val
.bool_values
->false_encode_token
){
511 buff
.put_cs(*p_td
.text
->val
.bool_values
->false_encode_token
);
512 encoded_length
+=p_td
.text
->
513 val
.bool_values
->false_encode_token
->lengthof();
515 buff
.put_s(5,(const unsigned char*)"false");
521 if(p_td
.text
->end_encode
){
522 buff
.put_cs(*p_td
.text
->end_encode
);
523 encoded_length
+=p_td
.text
->end_encode
->lengthof();
525 return encoded_length
;
528 int BOOLEAN::RAW_encode(const TTCN_Typedescriptor_t
& p_td
, RAW_enc_tree
& myleaf
) const
531 int loc_length
= p_td
.raw
->fieldlength
? p_td
.raw
->fieldlength
: 1;
532 int length
= (loc_length
+ 7) / 8;
535 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
536 "Encoding an unbound value.");
539 else tmp
= boolean_value
? 0xFF : 0x00;
540 // myleaf.ext_bit=EXT_BIT_NO;
541 if (myleaf
.must_free
) Free(myleaf
.body
.leaf
.data_ptr
);
542 if (length
> RAW_INT_ENC_LENGTH
) {
543 myleaf
.body
.leaf
.data_ptr
= bc
= (unsigned char*)Malloc(length
*sizeof(*bc
));
544 myleaf
.must_free
= TRUE
;
545 myleaf
.data_ptr_used
= TRUE
;
547 else bc
= myleaf
.body
.leaf
.data_array
;
549 memset(bc
, tmp
, length
* sizeof(*bc
));
550 if (boolean_value
&& loc_length
% 8 != 0) {
551 // remove the extra ones from the last octet
552 bc
[length
- 1] &= BitMaskTable
[loc_length
% 8];
554 return myleaf
.length
= loc_length
;
557 int BOOLEAN::RAW_decode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& buff
,
558 int limit
, raw_order_t top_bit_ord
, boolean no_err
, int /*sel_field*/,
559 boolean
/*first_call*/)
562 int prepaddlength
= buff
.increase_pos_padd(p_td
.raw
->prepadding
);
563 limit
-= prepaddlength
;
564 int decode_length
= p_td
.raw
->fieldlength
> 0 ? p_td
.raw
->fieldlength
: 1;
565 if (decode_length
> limit
) {
566 if (no_err
) return -TTCN_EncDec::ET_LEN_ERR
;
567 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
568 "There is not enough bits in the buffer to decode type %s (needed: %d, "
569 "found: %d).", p_td
.name
, decode_length
, limit
);
570 decode_length
= limit
;
572 int nof_unread_bits
= buff
.unread_len_bit();
573 if (decode_length
> nof_unread_bits
) {
574 if (no_err
) return -TTCN_EncDec::ET_INCOMPL_MSG
;
575 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG
,
576 "There is not enough bits in the buffer to decode type %s (needed: %d, "
577 "found: %d).", p_td
.name
, decode_length
, nof_unread_bits
);
578 decode_length
= nof_unread_bits
;
580 if (decode_length
< 0) return -1;
581 else if (decode_length
== 0) boolean_value
= FALSE
;
584 boolean orders
= FALSE
;
585 if (p_td
.raw
->bitorderinoctet
== ORDER_MSB
) orders
= TRUE
;
586 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
587 cp
.bitorder
= orders
? ORDER_MSB
: ORDER_LSB
;
589 if (p_td
.raw
->byteorder
== ORDER_MSB
) orders
= TRUE
;
590 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
591 cp
.byteorder
= orders
? ORDER_MSB
: ORDER_LSB
;
592 cp
.fieldorder
= p_td
.raw
->fieldorder
;
593 cp
.hexorder
= ORDER_LSB
;
594 int length
= (decode_length
+ 7) / 8;
595 unsigned char *data
= (unsigned char*)Malloc(length
*sizeof(unsigned char));
596 buff
.get_b((size_t)decode_length
, data
, cp
, top_bit_ord
);
597 if(decode_length
% 8){
598 data
[length
- 1] &= BitMaskTable
[decode_length
% 8];
600 unsigned char ch
= '\0';
601 for (int a
= 0; a
< length
; a
++) ch
|= data
[a
];
603 boolean_value
= ch
!= '\0';
606 decode_length
+= buff
.increase_pos_padd(p_td
.raw
->padding
);
607 return decode_length
+ prepaddlength
;
610 int BOOLEAN::XER_encode(const XERdescriptor_t
& p_td
,
611 TTCN_Buffer
& p_buf
, unsigned int flavor
, int indent
, embed_values_enc_struct_t
*) const
614 TTCN_EncDec_ErrorContext::error
615 (TTCN_EncDec::ET_UNBOUND
, "Encoding an unbound boolean value.");
617 int encoded_length
=(int)p_buf
.get_len();
619 int exer
= is_exer(flavor
);
621 flavor
|= (SIMPLE_TYPE
| BXER_EMPTY_ELEM
);
622 if (begin_xml(p_td
, p_buf
, flavor
, indent
, false) == -1) --encoded_length
;
625 if (p_td
.xer_bits
& XER_TEXT
) {
626 p_buf
.put_c(boolean_value
? '1' : '0');
629 if (boolean_value
) p_buf
.put_s(4, (cbyte
*)"true");
630 else p_buf
.put_s(5, (cbyte
*)"false");
634 if (boolean_value
) p_buf
.put_s(7, (cbyte
*)"<true/>");
635 else p_buf
.put_s(8, (cbyte
*)"<false/>");
638 end_xml(p_td
, p_buf
, flavor
, indent
, false);
640 return (int)p_buf
.get_len() - encoded_length
;
643 int BOOLEAN::XER_decode(const XERdescriptor_t
& p_td
, XmlReaderWrap
& reader
,
644 unsigned int flavor
, unsigned int /*flavor2*/, embed_values_dec_struct_t
*)
646 const boolean exer
= is_exer(flavor
);
647 int XMLValueList
= !exer
&& is_record_of(flavor
);
648 const boolean notag
= (exer
&& (p_td
.xer_bits
& (UNTAGGED
))) ||
649 is_exerlist(flavor
) || XMLValueList
;
650 int depth
= -1, success
, type
;
651 const char *value
= 0;
653 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
654 verify_name(reader
, p_td
, exer
);
655 value
= (const char *)reader
.Value();
658 for (success
= reader
.Ok(); success
== 1; success
= reader
.Read()) {
659 type
= reader
.NodeType();
660 if (!notag
&& depth
== -1) {
661 if (XML_READER_TYPE_ELEMENT
== type
) {
662 verify_name(reader
, p_td
, exer
);
663 depth
= reader
.Depth();
665 if (exer
&& (p_td
.dfeValue
!= 0) && reader
.IsEmptyElement()) {
666 *this = *static_cast<const BOOLEAN
*>(p_td
.dfeValue
);
673 else { // found the enclosing tag already
674 if (!exer
&& XML_READER_TYPE_ELEMENT
== type
) {
675 // this must be EmptyElement Boolean
676 if (!reader
.IsEmptyElement()) TTCN_EncDec_ErrorContext::error(
677 TTCN_EncDec::ET_INVAL_MSG
, "Boolean must be empty element");
678 value
= (const char*)reader
.LocalName();
680 else if (XML_READER_TYPE_TEXT
== type
) {
682 value
= (const char*)reader
.Value();
685 // Must not modify the buffer when attempting to find the selected alternative for USE-UNION
686 if (!exer
|| !(flavor
& EXIT_ON_ERROR
)) reader
.Read();
690 } // if not attribute
692 if (value
!= 0 && *value
!= 0) {
694 if (value
[1]=='\0' && (*value
& 0x3E) == '0')
697 boolean_value
= *value
== '1';
699 else if (!strcmp(value
, "true")) {
700 boolean_value
= true;
703 else if (!strcmp(value
, "false")) {
704 boolean_value
= false;
710 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) { // I am an attribute
711 // Let the caller do reader.AdvanceAttribute();
714 for (success
= reader
.Ok(); success
== 1; success
= reader
.Read()) {
715 type
= reader
.NodeType();
716 if (XML_READER_TYPE_END_ELEMENT
== type
) {
717 verify_end(reader
, p_td
, depth
, exer
);
718 reader
.Read(); // one last time
727 int BOOLEAN::JSON_encode(const TTCN_Typedescriptor_t
&, JSON_Tokenizer
& p_tok
) const
730 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
731 "Encoding an unbound boolean value.");
734 return p_tok
.put_next_token((boolean_value
) ? JSON_TOKEN_LITERAL_TRUE
: JSON_TOKEN_LITERAL_FALSE
, NULL
);
737 int BOOLEAN::JSON_decode(const TTCN_Typedescriptor_t
& p_td
, JSON_Tokenizer
& p_tok
, boolean p_silent
)
739 json_token_t token
= JSON_TOKEN_NONE
;
741 if (p_td
.json
->default_value
&& 0 == p_tok
.get_buffer_length()) {
742 // No JSON data in the buffer -> use default value
743 if (strcmp(p_td
.json
->default_value
, "true") == 0) {
744 token
= JSON_TOKEN_LITERAL_TRUE
;
747 token
= JSON_TOKEN_LITERAL_FALSE
;
750 dec_len
= p_tok
.get_next_token(&token
, NULL
, NULL
);
752 if (JSON_TOKEN_ERROR
== token
) {
753 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_BAD_TOKEN_ERROR
, "");
754 return JSON_ERROR_FATAL
;
756 else if (JSON_TOKEN_LITERAL_TRUE
== token
) {
758 boolean_value
= true;
760 else if (JSON_TOKEN_LITERAL_FALSE
== token
) {
762 boolean_value
= false;
766 return JSON_ERROR_INVALID_TOKEN
;
772 boolean
operator&&(boolean bool_value
, const BOOLEAN
& other_value
)
774 if (!bool_value
) return FALSE
;
775 other_value
.must_bound("The right operand of and operator is an unbound "
777 return other_value
.boolean_value
;
780 boolean
operator^(boolean bool_value
, const BOOLEAN
& other_value
)
782 other_value
.must_bound("The right operand of xor operator is an unbound "
784 return bool_value
!= other_value
.boolean_value
;
787 boolean
operator||(boolean bool_value
, const BOOLEAN
& other_value
)
789 if (bool_value
) return TRUE
;
790 other_value
.must_bound("The right operand of or operator is an unbound "
792 return other_value
.boolean_value
;
795 boolean
operator==(boolean bool_value
, const BOOLEAN
& other_value
)
797 other_value
.must_bound("The right operand of comparison is an unbound "
799 return bool_value
== other_value
.boolean_value
;
802 void BOOLEAN_template::clean_up()
804 if (template_selection
== VALUE_LIST
||
805 template_selection
== COMPLEMENTED_LIST
)
806 delete [] value_list
.list_value
;
807 template_selection
= UNINITIALIZED_TEMPLATE
;
810 void BOOLEAN_template::copy_template(const BOOLEAN_template
& other_value
)
812 switch (other_value
.template_selection
) {
814 single_value
= other_value
.single_value
;
821 case COMPLEMENTED_LIST
:
822 value_list
.n_values
= other_value
.value_list
.n_values
;
823 value_list
.list_value
= new BOOLEAN_template
[value_list
.n_values
];
824 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
825 value_list
.list_value
[i
].copy_template(
826 other_value
.value_list
.list_value
[i
]);
829 TTCN_error("Copying an uninitialized/unsupported boolean template.");
831 set_selection(other_value
);
834 BOOLEAN_template::BOOLEAN_template()
839 BOOLEAN_template::BOOLEAN_template(template_sel other_value
)
840 : Base_Template(other_value
)
842 check_single_selection(other_value
);
845 BOOLEAN_template::BOOLEAN_template(boolean other_value
)
846 : Base_Template(SPECIFIC_VALUE
)
848 single_value
= other_value
;
851 BOOLEAN_template::BOOLEAN_template(const BOOLEAN
& other_value
)
852 : Base_Template(SPECIFIC_VALUE
)
854 other_value
.must_bound("Creating a template from an unbound integer value.");
855 single_value
= other_value
.boolean_value
;
858 BOOLEAN_template::BOOLEAN_template(const OPTIONAL
<BOOLEAN
>& other_value
)
860 switch (other_value
.get_selection()) {
861 case OPTIONAL_PRESENT
:
862 set_selection(SPECIFIC_VALUE
);
863 single_value
= (boolean
)(const BOOLEAN
&)other_value
;
866 set_selection(OMIT_VALUE
);
869 TTCN_error("Creating a boolean template from an unbound optional field.");
873 BOOLEAN_template::BOOLEAN_template(const BOOLEAN_template
& other_value
)
876 copy_template(other_value
);
879 BOOLEAN_template::~BOOLEAN_template()
884 BOOLEAN_template
& BOOLEAN_template::operator=(template_sel other_value
)
886 check_single_selection(other_value
);
888 set_selection(other_value
);
892 BOOLEAN_template
& BOOLEAN_template::operator=(boolean other_value
)
895 set_selection(SPECIFIC_VALUE
);
896 single_value
= other_value
;
900 BOOLEAN_template
& BOOLEAN_template::operator=(const BOOLEAN
& other_value
)
902 other_value
.must_bound("Assignment of an unbound boolean value to a "
905 set_selection(SPECIFIC_VALUE
);
906 single_value
= other_value
.boolean_value
;
910 BOOLEAN_template
& BOOLEAN_template::operator=
911 (const OPTIONAL
<BOOLEAN
>& other_value
)
914 switch (other_value
.get_selection()) {
915 case OPTIONAL_PRESENT
:
916 set_selection(SPECIFIC_VALUE
);
917 single_value
= (boolean
)(const BOOLEAN
&)other_value
;
920 set_selection(OMIT_VALUE
);
923 TTCN_error("Assignment of an unbound optional field to a boolean "
929 BOOLEAN_template
& BOOLEAN_template::operator=
930 (const BOOLEAN_template
& other_value
)
932 if (&other_value
!= this) {
934 copy_template(other_value
);
939 boolean
BOOLEAN_template::match(boolean other_value
,
940 boolean
/* legacy */) const
942 switch (template_selection
) {
944 return single_value
== other_value
;
951 case COMPLEMENTED_LIST
:
952 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
953 if (value_list
.list_value
[i
].match(other_value
))
954 return template_selection
== VALUE_LIST
;
955 return template_selection
== COMPLEMENTED_LIST
;
957 TTCN_error("Matching with an uninitialized/unsupported boolean template.");
962 boolean
BOOLEAN_template::match(const BOOLEAN
& other_value
,
963 boolean
/* legacy */) const
965 if (!other_value
.is_bound()) return FALSE
;
966 return match(other_value
.boolean_value
);
969 boolean
BOOLEAN_template::valueof() const
971 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
972 TTCN_error("Performing valueof or "
973 "send operation on a non-specific boolean template.");
977 void BOOLEAN_template::set_type(template_sel template_type
,
978 unsigned int list_length
)
980 if (template_type
!= VALUE_LIST
&& template_type
!= COMPLEMENTED_LIST
)
981 TTCN_error("Setting an invalid list type for a boolean template.");
983 set_selection(template_type
);
984 value_list
.n_values
= list_length
;
985 value_list
.list_value
= new BOOLEAN_template
[list_length
];
988 BOOLEAN_template
& BOOLEAN_template::list_item(unsigned int list_index
)
990 if (template_selection
!= VALUE_LIST
&&
991 template_selection
!= COMPLEMENTED_LIST
)
992 TTCN_error("Accessing a list element of a non-list boolean template.");
993 if (list_index
>= value_list
.n_values
)
994 TTCN_error("Index overflow in a boolean value list template.");
995 return value_list
.list_value
[list_index
];
998 void BOOLEAN_template::log() const
1000 switch (template_selection
) {
1001 case SPECIFIC_VALUE
:
1002 TTCN_Logger::log_event_str(single_value
? "true" : "false");
1004 case COMPLEMENTED_LIST
:
1005 TTCN_Logger::log_event_str("complement ");
1008 TTCN_Logger::log_char('(');
1009 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++) {
1010 if (i
> 0) TTCN_Logger::log_event_str(", ");
1011 value_list
.list_value
[i
].log();
1013 TTCN_Logger::log_char(')');
1022 void BOOLEAN_template::log_match(const BOOLEAN
& match_value
,
1023 boolean
/* legacy */) const
1025 if (TTCN_Logger::VERBOSITY_COMPACT
== TTCN_Logger::get_matching_verbosity()
1026 && TTCN_Logger::get_logmatch_buffer_len() != 0) {
1027 TTCN_Logger::print_logmatch_buffer();
1028 TTCN_Logger::log_event_str(" := ");
1031 TTCN_Logger::log_event_str(" with ");
1033 if (match(match_value
)) TTCN_Logger::log_event_str(" matched");
1034 else TTCN_Logger::log_event_str(" unmatched");
1037 void BOOLEAN_template::set_param(Module_Param
& param
) {
1038 param
.basic_check(Module_Param::BC_TEMPLATE
, "boolean template");
1039 Module_Param_Ptr mp
= ¶m
;
1040 if (param
.get_type() == Module_Param::MP_Reference
) {
1041 mp
= param
.get_referenced_param();
1043 switch (mp
->get_type()) {
1044 case Module_Param::MP_Omit
:
1047 case Module_Param::MP_Any
:
1050 case Module_Param::MP_AnyOrNone
:
1051 *this = ANY_OR_OMIT
;
1053 case Module_Param::MP_List_Template
:
1054 case Module_Param::MP_ComplementList_Template
: {
1055 BOOLEAN_template temp
;
1056 temp
.set_type(mp
->get_type() == Module_Param::MP_List_Template
?
1057 VALUE_LIST
: COMPLEMENTED_LIST
, mp
->get_size());
1058 for (size_t i
=0; i
<mp
->get_size(); i
++) {
1059 temp
.list_item(i
).set_param(*mp
->get_elem(i
));
1063 case Module_Param::MP_Boolean
:
1064 *this = mp
->get_boolean();
1067 param
.type_error("boolean template");
1069 is_ifpresent
= param
.get_ifpresent() || mp
->get_ifpresent();
1072 Module_Param
* BOOLEAN_template::get_param(Module_Param_Name
& param_name
) const
1074 Module_Param
* mp
= NULL
;
1075 switch (template_selection
) {
1076 case UNINITIALIZED_TEMPLATE
:
1077 mp
= new Module_Param_Unbound();
1080 mp
= new Module_Param_Omit();
1083 mp
= new Module_Param_Any();
1086 mp
= new Module_Param_AnyOrNone();
1088 case SPECIFIC_VALUE
:
1089 mp
= new Module_Param_Boolean(single_value
);
1092 case COMPLEMENTED_LIST
: {
1093 if (template_selection
== VALUE_LIST
) {
1094 mp
= new Module_Param_List_Template();
1097 mp
= new Module_Param_ComplementList_Template();
1099 for (size_t i
= 0; i
< value_list
.n_values
; ++i
) {
1100 mp
->add_elem(value_list
.list_value
[i
].get_param(param_name
));
1107 mp
->set_ifpresent();
1112 void BOOLEAN_template::encode_text(Text_Buf
& text_buf
) const
1114 encode_text_base(text_buf
);
1115 switch (template_selection
) {
1120 case SPECIFIC_VALUE
:
1121 text_buf
.push_int(single_value
? 1 : 0);
1124 case COMPLEMENTED_LIST
:
1125 text_buf
.push_int(value_list
.n_values
);
1126 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1127 value_list
.list_value
[i
].encode_text(text_buf
);
1130 TTCN_error("Text encoder: Encoding an uninitialized/unsupported boolean "
1135 void BOOLEAN_template::decode_text(Text_Buf
& text_buf
)
1138 decode_text_base(text_buf
);
1139 switch (template_selection
) {
1144 case SPECIFIC_VALUE
: {
1145 int int_value
= text_buf
.pull_int().get_val();
1146 switch (int_value
) {
1148 single_value
= FALSE
;
1151 single_value
= TRUE
;
1154 TTCN_error("Text decoder: An invalid boolean value (%d) was received for "
1155 "a template.", int_value
);
1159 case COMPLEMENTED_LIST
:
1160 value_list
.n_values
= text_buf
.pull_int().get_val();
1161 value_list
.list_value
= new BOOLEAN_template
[value_list
.n_values
];
1162 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1163 value_list
.list_value
[i
].decode_text(text_buf
);
1166 TTCN_error("Text decoder: An unknown/unsupported selection was "
1167 "received for a boolean template.");
1171 boolean
BOOLEAN_template::is_present(boolean legacy
/* = FALSE */) const
1173 if (template_selection
==UNINITIALIZED_TEMPLATE
) return FALSE
;
1174 return !match_omit(legacy
);
1177 boolean
BOOLEAN_template::match_omit(boolean legacy
/* = FALSE */) const
1179 if (is_ifpresent
) return TRUE
;
1180 switch (template_selection
) {
1185 case COMPLEMENTED_LIST
:
1187 // legacy behavior: 'omit' can appear in the value/complement list
1188 for (unsigned int i
=0; i
<value_list
.n_values
; i
++)
1189 if (value_list
.list_value
[i
].match_omit())
1190 return template_selection
==VALUE_LIST
;
1191 return template_selection
==COMPLEMENTED_LIST
;
1193 // else fall through
1200 #ifndef TITAN_RUNTIME_2
1201 void BOOLEAN_template::check_restriction(template_res t_res
, const char* t_name
,
1202 boolean legacy
/* = FALSE */) const
1204 if (template_selection
==UNINITIALIZED_TEMPLATE
) return;
1205 switch ((t_name
&&(t_res
==TR_VALUE
))?TR_OMIT
:t_res
) {
1207 if (!is_ifpresent
&& template_selection
==SPECIFIC_VALUE
) return;
1210 if (!is_ifpresent
&& (template_selection
==OMIT_VALUE
||
1211 template_selection
==SPECIFIC_VALUE
)) return;
1214 if (!match_omit(legacy
)) return;
1219 TTCN_error("Restriction `%s' on template of type %s violated.",
1220 get_res_name(t_res
), t_name
? t_name
: "boolean");