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 ******************************************************************************/
25 #include "Hexstring.hh"
26 #include "../common/memory.h"
28 #include "String_struct.hh"
29 #include "Param_Types.hh"
36 #include "../common/dbgnew.hh"
40 // hexstring value class
42 /** The amount of memory needed for a string containing n hexadecimal digits. */
43 #define MEMORY_SIZE(n) (sizeof(hexstring_struct) - sizeof(int) + ((n) + 1) / 2)
45 void HEXSTRING::init_struct(int n_nibbles
)
49 TTCN_error("Initializing an hexstring with a negative length.");
51 else if (n_nibbles
== 0) {
52 /** This will represent the empty strings so they won't need allocated
53 * memory, this delays the memory allocation until it is really needed.
55 static hexstring_struct empty_string
= { 1, 0, "" };
56 val_ptr
= &empty_string
;
57 empty_string
.ref_count
++;
60 val_ptr
= (hexstring_struct
*) Malloc(MEMORY_SIZE(n_nibbles
));
61 val_ptr
->ref_count
= 1;
62 val_ptr
->n_nibbles
= n_nibbles
;
66 /** Return the nibble at index i
71 unsigned char HEXSTRING::get_nibble(int nibble_index
) const
73 unsigned char octet
= val_ptr
->nibbles_ptr
[nibble_index
/ 2];
75 return octet
>> 4; // odd nibble -> top
77 return octet
& 0x0F; // even nibble -> bottom
80 void HEXSTRING::set_nibble(int nibble_index
, unsigned char new_value
)
82 unsigned char old_octet
= val_ptr
->nibbles_ptr
[nibble_index
/ 2];
83 if (nibble_index
% 2) {
84 val_ptr
->nibbles_ptr
[nibble_index
/ 2] = (old_octet
& 0x0F) | (new_value
88 val_ptr
->nibbles_ptr
[nibble_index
/ 2] = (old_octet
& 0xF0) | (new_value
93 void HEXSTRING::copy_value()
95 if (val_ptr
== NULL
|| val_ptr
->n_nibbles
<= 0) TTCN_error(
96 "Internal error: Invalid internal data structure when copying "
97 "the memory area of a hexstring value.");
98 if (val_ptr
->ref_count
> 1) {
99 hexstring_struct
*old_ptr
= val_ptr
;
100 old_ptr
->ref_count
--;
101 init_struct(old_ptr
->n_nibbles
);
102 memcpy(val_ptr
->nibbles_ptr
, old_ptr
->nibbles_ptr
, (old_ptr
->n_nibbles
+ 1)
107 void HEXSTRING::clear_unused_nibble() const
109 if (val_ptr
->n_nibbles
% 2) val_ptr
->nibbles_ptr
[val_ptr
->n_nibbles
/ 2]
113 HEXSTRING::HEXSTRING(int n_nibbles
)
115 init_struct(n_nibbles
);
118 HEXSTRING::HEXSTRING()
123 HEXSTRING::HEXSTRING(int init_n_nibbles
, const unsigned char* init_nibbles
)
125 init_struct(init_n_nibbles
);
126 memcpy(val_ptr
->nibbles_ptr
, init_nibbles
, (init_n_nibbles
+ 1) / 2);
127 clear_unused_nibble();
130 HEXSTRING::HEXSTRING(const HEXSTRING
& other_value
) :
131 Base_Type(other_value
)
133 other_value
.must_bound("Initialization from an unbound hexstring value.");
134 val_ptr
= other_value
.val_ptr
;
135 val_ptr
->ref_count
++;
138 HEXSTRING::HEXSTRING(const HEXSTRING_ELEMENT
& other_value
)
140 other_value
.must_bound("Initialization from an unbound hexstring element.");
142 val_ptr
->nibbles_ptr
[0] = other_value
.get_nibble();
145 HEXSTRING::~HEXSTRING()
150 void HEXSTRING::clean_up()
152 if (val_ptr
!= NULL
) {
153 if (val_ptr
->ref_count
> 1)
154 val_ptr
->ref_count
--;
155 else if (val_ptr
->ref_count
== 1)
158 TTCN_error("Internal error: Invalid reference counter in a hexstring "
164 HEXSTRING
& HEXSTRING::operator=(const HEXSTRING
& other_value
)
166 other_value
.must_bound("Assignment of an unbound hexstring value.");
167 if (&other_value
!= this) {
169 val_ptr
= other_value
.val_ptr
;
170 val_ptr
->ref_count
++;
175 HEXSTRING
& HEXSTRING::operator=(const HEXSTRING_ELEMENT
& other_value
)
177 other_value
.must_bound("Assignment of an unbound hexstring element to a "
179 unsigned char nibble_value
= other_value
.get_nibble();
182 val_ptr
->nibbles_ptr
[0] = nibble_value
;
186 boolean
HEXSTRING::operator==(const HEXSTRING
& other_value
) const
188 must_bound("Unbound left operand of hexstring comparison.");
189 other_value
.must_bound("Unbound right operand of hexstring comparison.");
190 if (val_ptr
->n_nibbles
!= other_value
.val_ptr
->n_nibbles
) return FALSE
;
191 if (val_ptr
->n_nibbles
== 0) return TRUE
;
192 clear_unused_nibble();
193 other_value
.clear_unused_nibble();
194 return !memcmp(val_ptr
->nibbles_ptr
, other_value
.val_ptr
->nibbles_ptr
,
195 (val_ptr
->n_nibbles
+ 1) / 2);
198 boolean
HEXSTRING::operator==(const HEXSTRING_ELEMENT
& other_value
) const
200 must_bound("Unbound left operand of hexstring comparison.");
201 other_value
.must_bound("Unbound right operand of hexstring element "
203 if (val_ptr
->n_nibbles
!= 1) return FALSE
;
204 return get_nibble(0) == other_value
.get_nibble();
207 HEXSTRING
HEXSTRING::operator+(const HEXSTRING
& other_value
) const
209 must_bound("Unbound left operand of hexstring concatenation.");
210 other_value
.must_bound("Unbound right operand of hexstring concatenation.");
212 int left_n_nibbles
= val_ptr
->n_nibbles
;
213 if (left_n_nibbles
== 0) return other_value
;
215 int right_n_nibbles
= other_value
.val_ptr
->n_nibbles
;
216 if (right_n_nibbles
== 0) return *this;
218 int n_nibbles
= left_n_nibbles
+ right_n_nibbles
;
220 HEXSTRING
ret_val(n_nibbles
);
222 // the number of bytes used
223 int left_n_bytes
= (left_n_nibbles
+ 1) / 2;
224 int right_n_bytes
= (right_n_nibbles
+ 1) / 2;
226 // pointers to the data areas
227 const unsigned char *left_ptr
= val_ptr
->nibbles_ptr
;
228 const unsigned char *right_ptr
= other_value
.val_ptr
->nibbles_ptr
;
229 unsigned char *dest_ptr
= ret_val
.val_ptr
->nibbles_ptr
;
231 memcpy(dest_ptr
, left_ptr
, left_n_bytes
);
233 if (left_n_nibbles
% 2) {
234 dest_ptr
[left_n_bytes
- 1] &= 0x0F;
235 int n_bytes
= (n_nibbles
+ 1) / 2;
236 for (int i
= left_n_bytes
; i
< n_bytes
; i
++) {
237 unsigned char right_byte
= right_ptr
[i
- left_n_bytes
];
238 dest_ptr
[i
- 1] |= right_byte
<< 4;
239 dest_ptr
[i
] = right_byte
>> 4;
241 if (right_n_nibbles
% 2) dest_ptr
[n_bytes
- 1] |= right_ptr
[right_n_bytes
245 memcpy(dest_ptr
+ left_n_bytes
, right_ptr
, right_n_bytes
);
246 ret_val
.clear_unused_nibble();
251 HEXSTRING
HEXSTRING::operator+(const HEXSTRING_ELEMENT
& other_value
) const
253 must_bound("Unbound left operand of hexstring concatenation.");
254 other_value
.must_bound("Unbound right operand of hexstring element "
256 int n_nibbles
= val_ptr
->n_nibbles
;
257 HEXSTRING
ret_val(n_nibbles
+ 1);
258 memcpy(ret_val
.val_ptr
->nibbles_ptr
, val_ptr
->nibbles_ptr
, (n_nibbles
+ 1)
260 ret_val
.set_nibble(n_nibbles
, other_value
.get_nibble());
264 HEXSTRING
HEXSTRING::operator~() const
266 must_bound("Unbound hexstring operand of operator not4b.");
268 int n_bytes
= (val_ptr
->n_nibbles
+ 1) / 2;
269 if (n_bytes
== 0) return *this;
270 HEXSTRING
ret_val(val_ptr
->n_nibbles
);
271 for (int i
= 0; i
< n_bytes
; i
++) {
272 ret_val
.val_ptr
->nibbles_ptr
[i
] = ~val_ptr
->nibbles_ptr
[i
];
274 ret_val
.clear_unused_nibble();
278 HEXSTRING
HEXSTRING::operator&(const HEXSTRING
& other_value
) const
280 must_bound("Left operand of operator and4b is an unbound hexstring value.");
281 other_value
.must_bound("Right operand of operator and4b is an unbound "
283 int n_nibbles
= val_ptr
->n_nibbles
;
284 if (n_nibbles
!= other_value
.val_ptr
->n_nibbles
) TTCN_error("The hexstring "
285 "operands of operator and4b must have the same length.");
286 if (n_nibbles
== 0) return *this;
287 HEXSTRING
ret_val(n_nibbles
);
288 int n_bytes
= (n_nibbles
+ 1) / 2;
289 for (int i
= 0; i
< n_bytes
; i
++) {
290 ret_val
.val_ptr
->nibbles_ptr
[i
] = val_ptr
->nibbles_ptr
[i
]
291 & other_value
.val_ptr
->nibbles_ptr
[i
];
293 ret_val
.clear_unused_nibble();
297 HEXSTRING
HEXSTRING::operator&(const HEXSTRING_ELEMENT
& other_value
) const
299 must_bound("Left operand of operator and4b is an unbound hexstring value.");
300 other_value
.must_bound("Right operand of operator and4b is an unbound "
301 "hexstring element.");
302 if (val_ptr
->n_nibbles
!= 1) TTCN_error("The hexstring operands of operator "
303 "and4b must have the same length.");
304 unsigned char result
= get_nibble(0) & other_value
.get_nibble();
305 return HEXSTRING(1, &result
);
308 HEXSTRING
HEXSTRING::operator|(const HEXSTRING
& other_value
) const
310 must_bound("Left operand of operator or4b is an unbound hexstring value.");
311 other_value
.must_bound("Right operand of operator or4b is an unbound "
313 int n_nibbles
= val_ptr
->n_nibbles
;
314 if (n_nibbles
!= other_value
.val_ptr
->n_nibbles
) TTCN_error("The hexstring "
315 "operands of operator or4b must have the same length.");
316 if (n_nibbles
== 0) return *this;
317 HEXSTRING
ret_val(n_nibbles
);
318 int n_bytes
= (n_nibbles
+ 1) / 2;
319 for (int i
= 0; i
< n_bytes
; i
++) {
320 ret_val
.val_ptr
->nibbles_ptr
[i
] = val_ptr
->nibbles_ptr
[i
]
321 | other_value
.val_ptr
->nibbles_ptr
[i
];
323 ret_val
.clear_unused_nibble();
327 HEXSTRING
HEXSTRING::operator|(const HEXSTRING_ELEMENT
& other_value
) const
329 must_bound("Left operand of operator or4b is an unbound hexstring value.");
330 other_value
.must_bound("Right operand of operator or4b is an unbound "
331 "hexstring element.");
332 if (val_ptr
->n_nibbles
!= 1) TTCN_error("The hexstring operands of operator "
333 "or4b must have the same length.");
334 unsigned char result
= get_nibble(0) | other_value
.get_nibble();
335 return HEXSTRING(1, &result
);
338 HEXSTRING
HEXSTRING::operator^(const HEXSTRING
& other_value
) const
340 must_bound("Left operand of operator xor4b is an unbound hexstring value.");
341 other_value
.must_bound("Right operand of operator xor4b is an unbound "
343 int n_nibbles
= val_ptr
->n_nibbles
;
344 if (n_nibbles
!= other_value
.val_ptr
->n_nibbles
) TTCN_error("The hexstring "
345 "operands of operator xor4b must have the same length.");
346 if (n_nibbles
== 0) return *this;
347 HEXSTRING
ret_val(n_nibbles
);
348 int n_bytes
= (n_nibbles
+ 1) / 2;
349 for (int i
= 0; i
< n_bytes
; i
++) {
350 ret_val
.val_ptr
->nibbles_ptr
[i
] = val_ptr
->nibbles_ptr
[i
]
351 ^ other_value
.val_ptr
->nibbles_ptr
[i
];
353 ret_val
.clear_unused_nibble();
357 HEXSTRING
HEXSTRING::operator^(const HEXSTRING_ELEMENT
& other_value
) const
359 must_bound("Left operand of operator xor4b is an unbound hexstring value.");
360 other_value
.must_bound("Right operand of operator xor4b is an unbound "
361 "hexstring element.");
362 if (val_ptr
->n_nibbles
!= 1) TTCN_error("The hexstring operands of operator "
363 "xor4b must have the same length.");
364 unsigned char result
= get_nibble(0) ^ other_value
.get_nibble();
365 return HEXSTRING(1, &result
);
368 HEXSTRING
HEXSTRING::operator<<(int shift_count
) const
370 must_bound("Unbound hexstring operand of shift left operator.");
372 if (shift_count
> 0) {
373 int n_nibbles
= val_ptr
->n_nibbles
;
374 if (n_nibbles
== 0) return *this;
375 HEXSTRING
ret_val(n_nibbles
);
376 int n_bytes
= (n_nibbles
+ 1) / 2;
377 clear_unused_nibble();
378 if (shift_count
> n_nibbles
) shift_count
= n_nibbles
;
379 int shift_bytes
= shift_count
/ 2;
380 if (shift_count
% 2) {
382 for (; byte_count
< n_bytes
- shift_bytes
- 1; byte_count
++) {
383 ret_val
.val_ptr
->nibbles_ptr
[byte_count
]
384 = (val_ptr
->nibbles_ptr
[byte_count
+ shift_bytes
] >> 4)
385 | (val_ptr
->nibbles_ptr
[byte_count
+ shift_bytes
+ 1] << 4);
387 ret_val
.val_ptr
->nibbles_ptr
[n_bytes
- shift_bytes
- 1]
388 = val_ptr
->nibbles_ptr
[n_bytes
- 1] >> 4;
391 memcpy(ret_val
.val_ptr
->nibbles_ptr
, &val_ptr
->nibbles_ptr
[shift_count
392 / 2], (n_nibbles
- shift_count
+ 1) / 2);
394 memset(ret_val
.val_ptr
->nibbles_ptr
+ n_bytes
- shift_bytes
, 0, shift_bytes
);
397 else if (shift_count
== 0)
400 return *this >> (-shift_count
);
403 HEXSTRING
HEXSTRING::operator<<(const INTEGER
& shift_count
) const
405 shift_count
.must_bound("Unbound right operand of hexstring shift left "
407 return *this << (int) shift_count
;
410 HEXSTRING
HEXSTRING::operator>>(int shift_count
) const
412 must_bound("Unbound operand of hexstring shift right operator.");
414 if (shift_count
> 0) {
415 int n_nibbles
= val_ptr
->n_nibbles
;
416 if (n_nibbles
== 0) return *this;
417 HEXSTRING
ret_val(n_nibbles
);
418 int n_bytes
= (n_nibbles
+ 1) / 2;
419 clear_unused_nibble();
420 if (shift_count
> n_nibbles
) shift_count
= n_nibbles
;
421 int shift_bytes
= shift_count
/ 2;
422 memset(ret_val
.val_ptr
->nibbles_ptr
, 0, shift_bytes
);
423 if (shift_count
% 2) {
424 ret_val
.val_ptr
->nibbles_ptr
[shift_bytes
] = val_ptr
->nibbles_ptr
[0] << 4;
425 int byte_count
= shift_bytes
+ 1;
426 for (; byte_count
< n_bytes
; byte_count
++) {
427 ret_val
.val_ptr
->nibbles_ptr
[byte_count
]
428 = (val_ptr
->nibbles_ptr
[byte_count
- shift_bytes
- 1] >> 4)
429 | (val_ptr
->nibbles_ptr
[byte_count
- shift_bytes
] << 4);
433 memcpy(&ret_val
.val_ptr
->nibbles_ptr
[shift_bytes
], val_ptr
->nibbles_ptr
,
434 (n_nibbles
- shift_count
+ 1) / 2);
436 ret_val
.clear_unused_nibble();
439 else if (shift_count
== 0)
442 return *this << (-shift_count
);
445 HEXSTRING
HEXSTRING::operator>>(const INTEGER
& shift_count
) const
447 shift_count
.must_bound("Unbound right operand of hexstring shift right "
449 return *this >> (int) shift_count
;
452 HEXSTRING
HEXSTRING::operator<<=(int rotate_count
) const
454 must_bound("Unbound hexstring operand of rotate left operator.");
455 if (val_ptr
->n_nibbles
== 0) return *this;
456 if (rotate_count
>= 0) {
457 rotate_count
%= val_ptr
->n_nibbles
;
458 if (rotate_count
== 0) return *this;
459 return ((*this) << rotate_count
) | ((*this) >> (val_ptr
->n_nibbles
463 return *this >>= (-rotate_count
);
466 HEXSTRING
HEXSTRING::operator<<=(const INTEGER
& rotate_count
) const
468 rotate_count
.must_bound("Unbound right operand of hexstring rotate left "
470 return *this <<= (int) rotate_count
;
473 HEXSTRING
HEXSTRING::operator>>=(int rotate_count
) const
475 must_bound("Unbound hexstring operand of rotate right operator.");
476 if (val_ptr
->n_nibbles
== 0) return *this;
477 if (rotate_count
>= 0) {
478 rotate_count
%= val_ptr
->n_nibbles
;
479 if (rotate_count
== 0) return *this;
480 return ((*this) >> rotate_count
) | ((*this) << (val_ptr
->n_nibbles
484 return *this <<= (-rotate_count
);
487 HEXSTRING
HEXSTRING::operator>>=(const INTEGER
& rotate_count
) const
489 rotate_count
.must_bound("Unbound right operand of hexstring rotate right "
491 return *this >>= (int) rotate_count
;
494 HEXSTRING_ELEMENT
HEXSTRING::operator[](int index_value
)
496 if (val_ptr
== NULL
&& index_value
== 0) {
498 clear_unused_nibble();
499 return HEXSTRING_ELEMENT(FALSE
, *this, 0);
502 must_bound("Accessing an element of an unbound hexstring value.");
503 if (index_value
< 0) TTCN_error("Accessing an hexstring element using "
504 "a negative index (%d).", index_value
);
505 int n_nibbles
= val_ptr
->n_nibbles
;
506 if (index_value
> n_nibbles
) TTCN_error("Index overflow when accessing a "
507 "hexstring element: The index is %d, but the string has only %d "
508 "hexadecimal digits.", index_value
, n_nibbles
);
509 if (index_value
== n_nibbles
) {
510 if (val_ptr
->ref_count
== 1) {
511 if (n_nibbles
% 2 == 0) val_ptr
512 = (hexstring_struct
*) Realloc(val_ptr
, MEMORY_SIZE(n_nibbles
+ 1));
513 val_ptr
->n_nibbles
++;
516 hexstring_struct
*old_ptr
= val_ptr
;
517 old_ptr
->ref_count
--;
518 init_struct(n_nibbles
+ 1);
519 memcpy(val_ptr
->nibbles_ptr
, old_ptr
->nibbles_ptr
, (n_nibbles
+ 1) / 2);
521 return HEXSTRING_ELEMENT(FALSE
, *this, index_value
);
524 return HEXSTRING_ELEMENT(TRUE
, *this, index_value
);
528 HEXSTRING_ELEMENT
HEXSTRING::operator[](const INTEGER
& index_value
)
530 index_value
.must_bound("Indexing a hexstring value with an unbound integer "
532 return (*this)[(int) index_value
];
535 const HEXSTRING_ELEMENT
HEXSTRING::operator[](int index_value
) const
537 must_bound("Accessing an element of an unbound hexstring value.");
538 if (index_value
< 0) TTCN_error("Accessing an hexstring element using a "
539 "negative index (%d).", index_value
);
540 if (index_value
>= val_ptr
->n_nibbles
) TTCN_error("Index overflow when "
541 "accessing a hexstring element: The index is %d, but the string has only "
542 "%d hexadecimal digits.", index_value
, val_ptr
->n_nibbles
);
543 return HEXSTRING_ELEMENT(TRUE
, const_cast<HEXSTRING
&> (*this), index_value
);
546 const HEXSTRING_ELEMENT
HEXSTRING::operator[](const INTEGER
& index_value
) const
548 index_value
.must_bound("Indexing a hexstring value with an unbound integer "
550 return (*this)[(int) index_value
];
553 int HEXSTRING::lengthof() const
555 must_bound("Getting the length of an unbound hexstring value.");
556 return val_ptr
->n_nibbles
;
559 HEXSTRING::operator const unsigned char*() const
561 must_bound("Casting an unbound hexstring value to const unsigned char*.");
562 return val_ptr
->nibbles_ptr
;
565 void HEXSTRING::log() const
567 if (val_ptr
!= NULL
) {
568 TTCN_Logger::log_char('\'');
569 for (int i
= 0; i
< val_ptr
->n_nibbles
; i
++)
570 TTCN_Logger::log_hex(get_nibble(i
));
571 TTCN_Logger::log_event_str("'H");
574 TTCN_Logger::log_event_unbound();
578 void HEXSTRING::encode_text(Text_Buf
& text_buf
) const
580 must_bound("Text encoder: Encoding an unbound hexstring value");
581 int n_nibbles
= val_ptr
->n_nibbles
;
582 text_buf
.push_int(n_nibbles
);
583 if (n_nibbles
> 0) text_buf
.push_raw((n_nibbles
+ 1) / 2,
584 val_ptr
->nibbles_ptr
);
587 void HEXSTRING::decode_text(Text_Buf
& text_buf
)
589 int n_nibbles
= text_buf
.pull_int().get_val();
590 if (n_nibbles
< 0) TTCN_error(
591 "Text decoder: Invalid length was received for a hexstring.");
593 init_struct(n_nibbles
);
595 text_buf
.pull_raw((n_nibbles
+ 1) / 2, val_ptr
->nibbles_ptr
);
596 clear_unused_nibble();
600 void HEXSTRING::set_param(Module_Param
& param
) {
601 param
.basic_check(Module_Param::BC_VALUE
|Module_Param::BC_LIST
, "hexstring value");
602 Module_Param_Ptr mp
= ¶m
;
603 if (param
.get_type() == Module_Param::MP_Reference
) {
604 mp
= param
.get_referenced_param();
606 switch (mp
->get_type()) {
607 case Module_Param::MP_Hexstring
:
608 switch (param
.get_operation_type()) {
609 case Module_Param::OT_ASSIGN
: {
611 int n_nibbles
= mp
->get_string_size();
612 init_struct(n_nibbles
);
613 memcpy(val_ptr
->nibbles_ptr
, mp
->get_string_data(), (n_nibbles
+ 1) / 2);
614 clear_unused_nibble();
616 case Module_Param::OT_CONCAT
:
618 *this = *this + HEXSTRING(mp
->get_string_size(), (unsigned char*)mp
->get_string_data());
620 *this = HEXSTRING(mp
->get_string_size(), (unsigned char*)mp
->get_string_data());
624 TTCN_error("Internal error: HEXSTRING::set_param()");
627 case Module_Param::MP_Expression
:
628 if (mp
->get_expr_type() == Module_Param::EXPR_CONCATENATE
) {
629 HEXSTRING operand1
, operand2
;
630 operand1
.set_param(*mp
->get_operand1());
631 operand2
.set_param(*mp
->get_operand2());
632 if (param
.get_operation_type() == Module_Param::OT_CONCAT
) {
633 *this = *this + operand1
+ operand2
;
636 *this = operand1
+ operand2
;
640 param
.expr_type_error("a hexstring");
644 param
.type_error("hexstring value");
649 Module_Param
* HEXSTRING::get_param(Module_Param_Name
& /* param_name */) const
652 return new Module_Param_Unbound();
654 int n_bytes
= (val_ptr
->n_nibbles
+ 1) / 2;
655 unsigned char* val_cpy
= (unsigned char *)Malloc(n_bytes
);
656 memcpy(val_cpy
, val_ptr
->nibbles_ptr
, n_bytes
);
657 return new Module_Param_Hexstring(val_ptr
->n_nibbles
, val_cpy
);
660 void HEXSTRING::encode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& p_buf
,
661 TTCN_EncDec::coding_t p_coding
, ...) const
664 va_start(pvar
, p_coding
);
666 case TTCN_EncDec::CT_RAW
: {
667 TTCN_EncDec_ErrorContext
ec("While RAW-encoding type '%s': ", p_td
.name
);
668 if (!p_td
.raw
) TTCN_EncDec_ErrorContext::error_internal(
669 "No RAW descriptor available for type '%s'.", p_td
.name
);
673 RAW_enc_tree
root(true, NULL
, &rp
, 1, p_td
.raw
);
674 RAW_encode(p_td
, root
);
675 root
.put_to_buf(p_buf
);
677 case TTCN_EncDec::CT_XER
: {
678 TTCN_EncDec_ErrorContext
ec("While XER-encoding type '%s': ", p_td
.name
);
679 unsigned XER_coding
=va_arg(pvar
, unsigned);
680 XER_encode(*p_td
.xer
, p_buf
, XER_coding
, 0, 0);
682 case TTCN_EncDec::CT_JSON
: {
683 TTCN_EncDec_ErrorContext
ec("While JSON-encoding type '%s': ", p_td
.name
);
685 TTCN_EncDec_ErrorContext::error_internal
686 ("No JSON descriptor available for type '%s'.", p_td
.name
);
687 JSON_Tokenizer
tok(va_arg(pvar
, int) != 0);
688 JSON_encode(p_td
, tok
);
689 p_buf
.put_s(tok
.get_buffer_length(), (const unsigned char*)tok
.get_buffer());
692 TTCN_error("Unknown coding method requested to encode type '%s'", p_td
.name
);
697 void HEXSTRING::decode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& p_buf
,
698 TTCN_EncDec::coding_t p_coding
, ...)
701 va_start(pvar
, p_coding
);
703 case TTCN_EncDec::CT_RAW
: {
704 TTCN_EncDec_ErrorContext
ec("While RAW-decoding type '%s': ", p_td
.name
);
705 if (!p_td
.raw
) TTCN_EncDec_ErrorContext::error_internal(
706 "No RAW descriptor available for type '%s'.", p_td
.name
);
708 switch (p_td
.raw
->top_bit_order
) {
716 if (RAW_decode(p_td
, p_buf
, p_buf
.get_len() * 8, order
) < 0) ec
.error(
717 TTCN_EncDec::ET_INCOMPL_MSG
,
718 "Can not decode type '%s', because invalid or incomplete"
719 " message was received", p_td
.name
);
721 case TTCN_EncDec::CT_XER
: {
722 TTCN_EncDec_ErrorContext
ec("While XER-decoding type '%s': ", p_td
.name
);
723 unsigned XER_coding
=va_arg(pvar
, unsigned);
724 XmlReaderWrap
reader(p_buf
);
725 int success
= reader
.Read();
726 for (; success
==1; success
=reader
.Read()) {
727 int type
= reader
.NodeType();
728 if (type
==XML_READER_TYPE_ELEMENT
)
731 XER_decode(*p_td
.xer
, reader
, XER_coding
, XER_NONE
, 0);
732 size_t bytes
= reader
.ByteConsumed();
733 p_buf
.set_pos(bytes
);
735 case TTCN_EncDec::CT_JSON
: {
736 TTCN_EncDec_ErrorContext
ec("While JSON-decoding type '%s': ", p_td
.name
);
738 TTCN_EncDec_ErrorContext::error_internal
739 ("No JSON descriptor available for type '%s'.", p_td
.name
);
740 JSON_Tokenizer
tok((const char*)p_buf
.get_data(), p_buf
.get_len());
741 if(JSON_decode(p_td
, tok
, false)<0)
742 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
743 "Can not decode type '%s', because invalid or incomplete"
744 " message was received"
746 p_buf
.set_pos(tok
.get_buf_pos());
749 TTCN_error("Unknown coding method requested to decode type '%s'", p_td
.name
);
754 int HEXSTRING::RAW_encode(const TTCN_Typedescriptor_t
& p_td
,
755 RAW_enc_tree
& myleaf
) const
757 // unsigned char *bc;
759 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
760 "Encoding an unbound value.");
762 int nbits
= val_ptr
->n_nibbles
* 4;
763 int align_length
= p_td
.raw
->fieldlength
? p_td
.raw
->fieldlength
- nbits
: 0;
764 if ((nbits
+ align_length
) < val_ptr
->n_nibbles
* 4) {
765 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
766 "There is no sufficient bits to encode '%s': ", p_td
.name
);
767 nbits
= p_td
.raw
->fieldlength
;
771 if (myleaf
.must_free
) Free(myleaf
.body
.leaf
.data_ptr
);
773 myleaf
.must_free
= false;
774 myleaf
.data_ptr_used
= true;
775 myleaf
.body
.leaf
.data_ptr
= val_ptr
->nibbles_ptr
;
777 if (p_td
.raw
->endianness
== ORDER_MSB
)
778 myleaf
.align
= -align_length
;
780 myleaf
.align
= align_length
;
781 return myleaf
.length
= nbits
+ align_length
;
784 int HEXSTRING::RAW_decode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& buff
,
785 int limit
, raw_order_t top_bit_ord
, boolean no_err
, int /*sel_field*/,
786 boolean
/*first_call*/)
788 int prepaddlength
= buff
.increase_pos_padd(p_td
.raw
->prepadding
);
789 limit
-= prepaddlength
;
790 int decode_length
= p_td
.raw
->fieldlength
== 0
791 ? (limit
/ 4) * 4 : p_td
.raw
->fieldlength
;
792 if ( p_td
.raw
->fieldlength
> limit
793 || p_td
.raw
->fieldlength
> (int) buff
.unread_len_bit()) {
794 if (no_err
) return -TTCN_EncDec::ET_LEN_ERR
;
795 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
796 "There is not enough bits in the buffer to decode type %s.", p_td
.name
);
797 decode_length
= ((limit
> (int) buff
.unread_len_bit()
798 ? (int)buff
.unread_len_bit() : limit
) / 4) * 4;
802 if (p_td
.raw
->bitorderinoctet
== ORDER_MSB
) orders
= true;
803 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
804 cp
.bitorder
= orders
? ORDER_MSB
: ORDER_LSB
;
806 if (p_td
.raw
->byteorder
== ORDER_MSB
) orders
= true;
807 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
808 cp
.byteorder
= orders
? ORDER_MSB
: ORDER_LSB
;
809 cp
.fieldorder
= p_td
.raw
->fieldorder
;
810 cp
.hexorder
= p_td
.raw
->hexorder
;
812 init_struct(decode_length
/ 4);
813 buff
.get_b((size_t) decode_length
, val_ptr
->nibbles_ptr
, cp
, top_bit_ord
);
815 if (p_td
.raw
->length_restrition
!= -1) {
816 val_ptr
->n_nibbles
= p_td
.raw
->length_restrition
;
817 if (p_td
.raw
->endianness
== ORDER_MSB
) {
818 if ((decode_length
- val_ptr
->n_nibbles
* 4) % 8) {
819 int bound
= (decode_length
- val_ptr
->n_nibbles
* 4) % 8;
820 int maxindex
= (decode_length
- 1) / 8;
821 for (int a
= 0, b
= (decode_length
- val_ptr
->n_nibbles
* 4 - 1) / 8; a
822 < (val_ptr
->n_nibbles
* 4 + 7) / 8; a
++, b
++) {
823 val_ptr
->nibbles_ptr
[a
] = val_ptr
->nibbles_ptr
[b
] >> bound
;
825 val_ptr
->nibbles_ptr
[a
] = val_ptr
->nibbles_ptr
[b
+ 1] << (8 - bound
);
828 else memmove(val_ptr
->nibbles_ptr
,
829 val_ptr
->nibbles_ptr
+ (decode_length
- val_ptr
->n_nibbles
* 4) / 8,
830 val_ptr
->n_nibbles
* 8 * sizeof(unsigned char));
834 /* for(int a=0; a<decode_length/8; a++)
835 val_ptr->nibbles_ptr[a]= ((val_ptr->nibbles_ptr[a]<<4)&0xf0) |
836 ((val_ptr->nibbles_ptr[a]>>4)&0x0f);*/
837 decode_length
+= buff
.increase_pos_padd(p_td
.raw
->padding
);
838 clear_unused_nibble();
839 return decode_length
+ prepaddlength
;
842 // From Charstring.cc
843 extern char base64_decoder_table
[256];
844 extern const char cb64
[];
846 int HEXSTRING::XER_encode(const XERdescriptor_t
& p_td
,
847 TTCN_Buffer
& p_buf
, unsigned int flavor
, int indent
, embed_values_enc_struct_t
*) const
850 TTCN_EncDec_ErrorContext::error
851 (TTCN_EncDec::ET_UNBOUND
, "Encoding an unbound hexstring value.");
853 int exer
= is_exer(flavor
|= SIMPLE_TYPE
);
854 // SIMPLE_TYPE has no influence on is_exer, we set it for later
855 int encoded_length
=(int)p_buf
.get_len();
856 int empty_element
= val_ptr
==NULL
|| val_ptr
->n_nibbles
== 0;
858 flavor
&= ~XER_RECOF
; // octetstring doesn't care
859 begin_xml(p_td
, p_buf
, flavor
, indent
, empty_element
);
861 if (exer
&& (p_td
.xer_bits
& BASE_64
)) {
863 size_t clear_len
= (val_ptr
->n_nibbles
+ 1) / 2; // lengthof is in nibbles
864 const unsigned char * in
= val_ptr
->nibbles_ptr
;
866 /* Encode (up to) 6 nibbles of cleartext into 4 bytes of base64.
867 * This is different from Octetstring.cc because hexstring's
868 * big-endian data storage. */
869 for (size_t i
= 0; i
< clear_len
; i
+= 3) {
870 unsigned char first
= in
[i
],
871 second
= ((i
+1 < clear_len
) ? in
[i
+1] :0),
872 third
= ((i
+2 < clear_len
) ? in
[i
+2] :0);
874 p_buf
.put_c(cb64
[(first
& 0x0F) << 2 | first
>> 6]);
875 p_buf
.put_c(cb64
[(first
& 0x30) | (second
& 0x0F)]);
876 p_buf
.put_c(i
+1 >= clear_len
? '='
877 : cb64
[(second
& 0xF0) >> 2 | (third
& 0x0C) >> 2]);
878 p_buf
.put_c( i
+2 >= clear_len
? '='
879 : cb64
[(third
& 0x03) << 4 | (third
& 0xF0) >> 4]);
883 CHARSTRING val
= hex2str(*this);
884 p_buf
.put_string(val
);
887 end_xml(p_td
, p_buf
, flavor
, indent
, empty_element
);
889 return (int)p_buf
.get_len() - encoded_length
;
893 unsigned int xlate_hs(cbyte
*in
, int phase
, unsigned char*dest
) {
894 static unsigned char nbytes
[4] = { 3,1,1,2 };
895 unsigned char out
[4];
897 out
[0] = in
[0] >> 2 | (in
[0] & 3) << 6 | (in
[1] & 0x30);
898 out
[1] = (in
[1] & 0x0F) | (in
[2] & 0x3C) << 2;
899 out
[2] = (in
[3] & 0x0F) << 4 | (in
[3] & 0x30) >> 4 | (in
[2] & 3) << 2;
900 memcpy(dest
, out
, nbytes
[phase
]);
901 return nbytes
[phase
];
905 /* Here's how the bits get transferred to and from Base64:
907 Titan stores the hex digits in "little endian order", the first (index 0)
908 goes into the lower nibble, the second goes into the high nibble
909 of the first byte. So, For the hexstring value 'DECAFBAD'H,
910 Titan stores the following bytes: ED AC BF DA
912 Because of this, the bit shifting is different. The first three bytes
914 3x8 bits: eeeedddd aaaacccc bbbbffff
916 4x6 bits: ddddee eecccc aaaaff ffbbbb
920 int HEXSTRING::XER_decode(const XERdescriptor_t
& p_td
, XmlReaderWrap
& reader
,
921 unsigned int flavor
, unsigned int /*flavor2*/, embed_values_dec_struct_t
*)
923 int exer
= is_exer(flavor
);
924 int success
= reader
.Ok(), depth
= -1, type
;
925 boolean own_tag
= !is_exerlist(flavor
) && !(exer
&& (p_td
.xer_bits
& UNTAGGED
));
927 const char * value
= 0;
928 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
929 const char * name
= verify_name(reader
, p_td
, exer
);
933 if (own_tag
) for (; success
== 1; success
= reader
.Read()) {
934 type
= reader
.NodeType();
935 if (XML_READER_TYPE_ELEMENT
== type
) {
936 verify_name(reader
, p_td
, exer
);
937 depth
= reader
.Depth();
938 if (reader
.IsEmptyElement()) {
939 if (exer
&& p_td
.dfeValue
!= 0) {
940 *this = *static_cast<const HEXSTRING
*> (p_td
.dfeValue
);
947 else if (XML_READER_TYPE_TEXT
== type
&& depth
!= -1) break;
948 else if (XML_READER_TYPE_END_ELEMENT
== type
) {
949 // End tag without intervening #text == empty content
950 verify_end(reader
, p_td
, depth
, exer
);
951 if (exer
&& p_td
.dfeValue
!= 0) {
952 *this = *static_cast<const HEXSTRING
*>(p_td
.dfeValue
);
960 type
= reader
.NodeType();
961 if (success
== 1 && (XML_READER_TYPE_TEXT
== type
|| XML_READER_TYPE_ATTRIBUTE
== type
)) {
962 value
= (const char *)reader
.Value();
963 size_t len
= value
? strlen(value
) : 0;
965 if (exer
&& (p_td
.xer_bits
& BASE_64
)) {
969 init_struct(len
* 3 / 2); // 4 bytes decoded into 3 octets (6 nibbles)
970 unsigned char * dest
= val_ptr
->nibbles_ptr
;
972 for (size_t o
=0; o
<len
; ++o
) {
973 xmlChar c
= value
[o
];
974 if(c
== '=') { // padding starts
975 dest
+= xlate_hs(in
, phase
, dest
);
979 int val
= base64_decoder_table
[c
];
982 phase
= (phase
+ 1) % 4;
984 dest
+= xlate_hs(in
,phase
, dest
);
985 in
[0]=in
[1]=in
[2]=in
[3]=0;
988 else if (exer
&& (flavor
& EXIT_ON_ERROR
)) {
992 TTCN_EncDec_ErrorContext::warning(
993 /* if this was an error... TTCN_EncDec::ET_INVAL_MSG,*/
994 "Invalid character for Base64 '%02X'", c
);
998 val_ptr
->n_nibbles
= (dest
- val_ptr
->nibbles_ptr
) * 2;
1001 else { // not base64
1004 for (size_t i
= 0; i
< len
; ++i
) {
1005 unsigned char nibble
= char_to_hexdigit(value
[i
]);
1006 if (nibble
> 0x0F) {
1007 if (exer
&& (flavor
& EXIT_ON_ERROR
)) {
1011 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG
,
1012 "The hexstring value may contain hexadecimal digits only. "
1013 "Character \"%c\" was found.", value
[i
]);
1017 //val_ptr->nibbles_ptr[i] = nibble;
1018 set_nibble(i
, nibble
);
1023 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
1024 // Let the caller do reader.AdvanceAttribute();
1027 if (own_tag
) for (success
= reader
.Read(); success
== 1; success
= reader
.Read()) {
1028 type
= reader
.NodeType();
1029 if (XML_READER_TYPE_END_ELEMENT
== type
) {
1030 verify_end(reader
, p_td
, depth
, exer
);
1031 if (val_ptr
== 0 && p_td
.dfeValue
!= 0) {
1032 // The end tag must have followed the start tag
1033 *this = *static_cast<const HEXSTRING
*>(p_td
.dfeValue
);
1035 reader
.Read(); // one last time
1040 return 1; // decode successful
1043 int HEXSTRING::JSON_encode(const TTCN_Typedescriptor_t
&, JSON_Tokenizer
& p_tok
) const
1046 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
1047 "Encoding an unbound hexstring value.");
1051 char* tmp_str
= (char*)Malloc(val_ptr
->n_nibbles
+ 3);
1053 tmp_str
[val_ptr
->n_nibbles
+ 1] = '\"';
1054 for(int i
= 0; i
< val_ptr
->n_nibbles
; ++i
) {
1056 tmp_str
[i
+ 1] = hexdigit_to_char(val_ptr
->nibbles_ptr
[i
/ 2] >> 4);
1058 tmp_str
[i
+ 1] = hexdigit_to_char(val_ptr
->nibbles_ptr
[i
/ 2] & 0x0F);
1061 tmp_str
[val_ptr
->n_nibbles
+ 2] = 0;
1062 int enc_len
= p_tok
.put_next_token(JSON_TOKEN_STRING
, tmp_str
);
1067 int HEXSTRING::JSON_decode(const TTCN_Typedescriptor_t
& p_td
, JSON_Tokenizer
& p_tok
, boolean p_silent
)
1069 json_token_t token
= JSON_TOKEN_NONE
;
1071 size_t value_len
= 0;
1072 boolean error
= false;
1074 boolean use_default
= p_td
.json
->default_value
&& 0 == p_tok
.get_buffer_length();
1076 // No JSON data in the buffer -> use default value
1077 value
= (char*)p_td
.json
->default_value
;
1078 value_len
= strlen(value
);
1080 dec_len
= p_tok
.get_next_token(&token
, &value
, &value_len
);
1082 if (JSON_TOKEN_ERROR
== token
) {
1083 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_BAD_TOKEN_ERROR
, "");
1084 return JSON_ERROR_FATAL
;
1086 else if (JSON_TOKEN_STRING
== token
|| use_default
) {
1087 if (use_default
|| (value_len
> 2 && value
[0] == '\"' && value
[value_len
- 1] == '\"')) {
1089 // The default value doesn't have quotes around it
1093 init_struct(value_len
);
1094 for (size_t i
= 0; i
< value_len
; ++i
) {
1095 unsigned char nibble
= char_to_hexdigit(value
[i
]);
1096 if (nibble
<= 0x0F) {
1097 set_nibble(i
, nibble
);
1106 return JSON_ERROR_INVALID_TOKEN
;
1110 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_FORMAT_ERROR
, "string", "hexstring");
1114 return JSON_ERROR_FATAL
;
1120 //---------------------- hexstring element class ----------------------
1122 HEXSTRING_ELEMENT::HEXSTRING_ELEMENT(boolean par_bound_flag
,
1123 HEXSTRING
& par_str_val
, int par_nibble_pos
) :
1124 bound_flag(par_bound_flag
), str_val(par_str_val
), nibble_pos(par_nibble_pos
)
1128 HEXSTRING_ELEMENT
& HEXSTRING_ELEMENT::operator=(
1129 const HEXSTRING_ELEMENT
& other_value
)
1131 other_value
.must_bound("Assignment of an unbound hexstring element.");
1133 str_val
.copy_value();
1134 str_val
.set_nibble(nibble_pos
, other_value
.str_val
.get_nibble(
1135 other_value
.nibble_pos
));
1139 HEXSTRING_ELEMENT
& HEXSTRING_ELEMENT::operator=(const HEXSTRING
& other_value
)
1141 other_value
.must_bound("Assignment of unbound hexstring value.");
1142 if (other_value
.lengthof() != 1) TTCN_error(
1143 "Assignment of a hexstring value "
1144 "with length other than 1 to a hexstring element.");
1146 str_val
.copy_value();
1147 str_val
.set_nibble(nibble_pos
, other_value
.get_nibble(0));
1151 boolean
HEXSTRING_ELEMENT::operator==(const HEXSTRING_ELEMENT
& other_value
) const
1153 must_bound("Unbound left operand of hexstring element comparison.");
1154 other_value
.must_bound("Unbound right operand of hexstring comparison.");
1155 return str_val
.get_nibble(nibble_pos
) == other_value
.str_val
.get_nibble(
1156 other_value
.nibble_pos
);
1159 boolean
HEXSTRING_ELEMENT::operator==(const HEXSTRING
& other_value
) const
1161 must_bound("Unbound left operand of hexstring element comparison.");
1162 other_value
.must_bound("Unbound right operand of hexstring element "
1164 if (other_value
.val_ptr
->n_nibbles
!= 1) return FALSE
;
1165 return str_val
.get_nibble(nibble_pos
) == other_value
.get_nibble(0);
1168 HEXSTRING
HEXSTRING_ELEMENT::operator+(const HEXSTRING
& other_value
) const
1170 must_bound("Unbound left operand of hexstring element concatenation.");
1171 other_value
.must_bound("Unbound right operand of hexstring concatenation.");
1172 int n_nibbles
= other_value
.val_ptr
->n_nibbles
;
1173 HEXSTRING
ret_val(n_nibbles
+ 1);
1174 const unsigned char *src_ptr
= other_value
.val_ptr
->nibbles_ptr
;
1175 unsigned char *dest_ptr
= ret_val
.val_ptr
->nibbles_ptr
;
1176 dest_ptr
[0] = str_val
.get_nibble(nibble_pos
);
1177 // bytes in the result minus 1
1178 int n_complete_bytes
= n_nibbles
/ 2;
1179 for (int i
= 0; i
< n_complete_bytes
; i
++) {
1180 unsigned char right_octet
= src_ptr
[i
];
1181 dest_ptr
[i
] |= right_octet
<< 4;
1182 dest_ptr
[i
+ 1] = right_octet
>> 4;
1184 if (n_nibbles
% 2) dest_ptr
[n_complete_bytes
] |= src_ptr
[n_complete_bytes
]
1189 HEXSTRING
HEXSTRING_ELEMENT::operator+(const HEXSTRING_ELEMENT
& other_value
) const
1191 must_bound("Unbound left operand of hexstring element concatenation.");
1192 other_value
.must_bound("Unbound right operand of hexstring element "
1194 unsigned char result
= str_val
.get_nibble(nibble_pos
)
1195 | (other_value
.str_val
.get_nibble(other_value
.nibble_pos
) << 4);
1196 return HEXSTRING(2, &result
);
1199 HEXSTRING
HEXSTRING_ELEMENT::operator~() const
1201 must_bound("Unbound hexstring element operand of operator not4b.");
1202 unsigned char result
= ~str_val
.get_nibble(nibble_pos
) & 0x0F;
1203 return HEXSTRING(1, &result
);
1206 HEXSTRING
HEXSTRING_ELEMENT::operator&(const HEXSTRING
& other_value
) const
1208 must_bound("Left operand of operator and4b is an unbound hexstring element.");
1209 other_value
.must_bound("Right operand of operator and4b is an unbound "
1210 "hexstring value.");
1211 if (other_value
.val_ptr
->n_nibbles
!= 1) TTCN_error("The hexstring operands "
1212 "of operator and4b must have the same length.");
1213 unsigned char result
= str_val
.get_nibble(nibble_pos
)
1214 & other_value
.get_nibble(0);
1215 return HEXSTRING(1, &result
);
1218 HEXSTRING
HEXSTRING_ELEMENT::operator&(const HEXSTRING_ELEMENT
& other_value
) const
1220 must_bound("Left operand of operator and4b is an unbound hexstring element.");
1221 other_value
.must_bound("Right operand of operator and4b is an unbound "
1222 "hexstring element.");
1223 unsigned char result
= str_val
.get_nibble(nibble_pos
)
1224 & other_value
.str_val
.get_nibble(other_value
.nibble_pos
);
1225 return HEXSTRING(1, &result
);
1228 HEXSTRING
HEXSTRING_ELEMENT::operator|(const HEXSTRING
& other_value
) const
1230 must_bound("Left operand of operator or4b is an unbound hexstring element.");
1231 other_value
.must_bound("Right operand of operator or4b is an unbound "
1232 "hexstring value.");
1233 if (other_value
.val_ptr
->n_nibbles
!= 1) TTCN_error("The hexstring operands "
1234 "of operator or4b must have the same length.");
1235 unsigned char result
= str_val
.get_nibble(nibble_pos
)
1236 | other_value
.get_nibble(0);
1237 return HEXSTRING(1, &result
);
1240 HEXSTRING
HEXSTRING_ELEMENT::operator|(const HEXSTRING_ELEMENT
& other_value
) const
1242 must_bound("Left operand of operator or4b is an unbound hexstring element.");
1243 other_value
.must_bound("Right operand of operator or4b is an unbound "
1244 "hexstring element.");
1245 unsigned char result
= str_val
.get_nibble(nibble_pos
)
1246 | other_value
.str_val
.get_nibble(other_value
.nibble_pos
);
1247 return HEXSTRING(1, &result
);
1250 HEXSTRING
HEXSTRING_ELEMENT::operator^(const HEXSTRING
& other_value
) const
1252 must_bound("Left operand of operator xor4b is an unbound hexstring element.");
1253 other_value
.must_bound("Right operand of operator xor4b is an unbound "
1254 "hexstring value.");
1255 if (other_value
.val_ptr
->n_nibbles
!= 1) TTCN_error("The hexstring operands "
1256 "of operator xor4b must have the same length.");
1257 unsigned char result
= str_val
.get_nibble(nibble_pos
)
1258 ^ other_value
.get_nibble(0);
1259 return HEXSTRING(1, &result
);
1262 HEXSTRING
HEXSTRING_ELEMENT::operator^(const HEXSTRING_ELEMENT
& other_value
) const
1264 must_bound("Left operand of operator xor4b is an unbound hexstring element.");
1265 other_value
.must_bound("Right operand of operator xor4b is an unbound "
1266 "hexstring element.");
1267 unsigned char result
= str_val
.get_nibble(nibble_pos
)
1268 ^ other_value
.str_val
.get_nibble(other_value
.nibble_pos
);
1269 return HEXSTRING(1, &result
);
1272 unsigned char HEXSTRING_ELEMENT::get_nibble() const
1274 return str_val
.get_nibble(nibble_pos
);
1277 void HEXSTRING_ELEMENT::log() const
1280 TTCN_Logger::log_char('\'');
1281 TTCN_Logger::log_hex(str_val
.get_nibble(nibble_pos
));
1282 TTCN_Logger::log_event_str("'H");
1285 TTCN_Logger::log_event_unbound();
1289 //---------------------- hexstring template class ----------------------
1291 void HEXSTRING_template::clean_up()
1293 switch (template_selection
) {
1295 case COMPLEMENTED_LIST
:
1296 delete[] value_list
.list_value
;
1298 case STRING_PATTERN
:
1299 if (pattern_value
->ref_count
> 1)
1300 pattern_value
->ref_count
--;
1301 else if (pattern_value
->ref_count
== 1)
1302 Free(pattern_value
);
1304 TTCN_error("Internal error: Invalid reference counter in a hexstring "
1308 if (dec_match
->ref_count
> 1) {
1309 dec_match
->ref_count
--;
1311 else if (dec_match
->ref_count
== 1) {
1312 delete dec_match
->instance
;
1316 TTCN_error("Internal error: Invalid reference counter in a "
1317 "decoded content match.");
1323 template_selection
= UNINITIALIZED_TEMPLATE
;
1326 void HEXSTRING_template::copy_template(const HEXSTRING_template
& other_value
)
1328 switch (other_value
.template_selection
) {
1329 case SPECIFIC_VALUE
:
1330 single_value
= other_value
.single_value
;
1337 case COMPLEMENTED_LIST
:
1338 value_list
.n_values
= other_value
.value_list
.n_values
;
1339 value_list
.list_value
= new HEXSTRING_template
[value_list
.n_values
];
1340 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1341 value_list
.list_value
[i
].copy_template(
1342 other_value
.value_list
.list_value
[i
]);
1344 case STRING_PATTERN
:
1345 pattern_value
= other_value
.pattern_value
;
1346 pattern_value
->ref_count
++;
1349 dec_match
= other_value
.dec_match
;
1350 dec_match
->ref_count
++;
1353 TTCN_error("Copying an uninitialized/unsupported hexstring template.");
1355 set_selection(other_value
);
1359 This is the same algorithm that match_array uses
1360 to match 'record of' types.
1361 The only differences are: how two elements are matched and
1362 how an asterisk or ? is identified in the template
1364 boolean
HEXSTRING_template::match_pattern(
1365 const hexstring_pattern_struct
*string_pattern
,
1366 const HEXSTRING::hexstring_struct
*string_value
)
1368 // the empty pattern matches the empty hexstring only
1369 if (string_pattern
->n_elements
== 0) return string_value
->n_nibbles
== 0;
1371 int value_index
= 0;
1372 unsigned int template_index
= 0;
1373 int last_asterisk
= -1;
1374 int last_value_to_asterisk
= -1;
1375 //the following variables are just to speed up the function
1376 unsigned char pattern_element
;
1377 unsigned char octet
;
1378 unsigned char hex_digit
;
1381 pattern_element
= string_pattern
->elements_ptr
[template_index
];
1382 if (pattern_element
< 16) {
1383 octet
= string_value
->nibbles_ptr
[value_index
/ 2];
1384 if (value_index
% 2)
1385 hex_digit
= octet
>> 4;
1387 hex_digit
= octet
& 0x0F;
1388 if (hex_digit
== pattern_element
) {
1393 if (last_asterisk
== -1) return FALSE
;
1394 template_index
= last_asterisk
+ 1;
1395 value_index
= ++last_value_to_asterisk
;
1398 else if (pattern_element
== 16) {//?
1402 else if (pattern_element
== 17) {//*
1403 last_asterisk
= template_index
++;
1404 last_value_to_asterisk
= value_index
;
1407 TTCN_error("Internal error: invalid element in a hexstring "
1410 if (value_index
== string_value
->n_nibbles
&& template_index
1411 == string_pattern
->n_elements
) {
1414 else if (template_index
== string_pattern
->n_elements
) {
1415 if (string_pattern
->elements_ptr
[template_index
- 1] == 17) {
1418 else if (last_asterisk
== -1) {
1422 template_index
= last_asterisk
+ 1;
1423 value_index
= ++last_value_to_asterisk
;
1426 else if (value_index
== string_value
->n_nibbles
) {
1427 while (template_index
< string_pattern
->n_elements
1428 && string_pattern
->elements_ptr
[template_index
] == 17)
1431 return template_index
== string_pattern
->n_elements
;
1436 HEXSTRING_template::HEXSTRING_template()
1440 HEXSTRING_template::HEXSTRING_template(template_sel other_value
) :
1441 Restricted_Length_Template(other_value
)
1443 check_single_selection(other_value
);
1446 HEXSTRING_template::HEXSTRING_template(const HEXSTRING
& other_value
) :
1447 Restricted_Length_Template(SPECIFIC_VALUE
), single_value(other_value
)
1451 HEXSTRING_template::HEXSTRING_template(const HEXSTRING_ELEMENT
& other_value
) :
1452 Restricted_Length_Template(SPECIFIC_VALUE
), single_value(other_value
)
1456 HEXSTRING_template::HEXSTRING_template(const OPTIONAL
<HEXSTRING
>& other_value
)
1458 switch (other_value
.get_selection()) {
1459 case OPTIONAL_PRESENT
:
1460 set_selection(SPECIFIC_VALUE
);
1461 single_value
= (const HEXSTRING
&) other_value
;
1464 set_selection(OMIT_VALUE
);
1467 TTCN_error("Creating a hexstring template from an unbound optional field.");
1471 HEXSTRING_template::HEXSTRING_template(unsigned int n_elements
,
1472 const unsigned char *pattern_elements
) :
1473 Restricted_Length_Template(STRING_PATTERN
)
1476 = (hexstring_pattern_struct
*) Malloc(sizeof(hexstring_pattern_struct
) + n_elements
- 1);
1477 pattern_value
->ref_count
= 1;
1478 pattern_value
->n_elements
= n_elements
;
1479 memcpy(pattern_value
->elements_ptr
, pattern_elements
, n_elements
);
1482 HEXSTRING_template::HEXSTRING_template(const HEXSTRING_template
& other_value
) :
1483 Restricted_Length_Template()
1485 copy_template(other_value
);
1488 HEXSTRING_template::~HEXSTRING_template()
1493 HEXSTRING_template
& HEXSTRING_template::operator=(template_sel other_value
)
1495 check_single_selection(other_value
);
1497 set_selection(other_value
);
1501 HEXSTRING_template
& HEXSTRING_template::operator=(const HEXSTRING
& other_value
)
1503 other_value
.must_bound("Assignment of an unbound hexstring value to a "
1506 set_selection(SPECIFIC_VALUE
);
1507 single_value
= other_value
;
1511 HEXSTRING_template
& HEXSTRING_template::operator=(
1512 const HEXSTRING_ELEMENT
& other_value
)
1514 other_value
.must_bound("Assignment of an unbound hexstring element to a "
1517 set_selection(SPECIFIC_VALUE
);
1518 single_value
= other_value
;
1522 HEXSTRING_template
& HEXSTRING_template::operator=(
1523 const OPTIONAL
<HEXSTRING
>& other_value
)
1526 switch (other_value
.get_selection()) {
1527 case OPTIONAL_PRESENT
:
1528 set_selection(SPECIFIC_VALUE
);
1529 single_value
= (const HEXSTRING
&) other_value
;
1532 set_selection(OMIT_VALUE
);
1535 TTCN_error("Assignment of an unbound optional field to a hexstring "
1541 HEXSTRING_template
& HEXSTRING_template::operator=(
1542 const HEXSTRING_template
& other_value
)
1544 if (&other_value
!= this) {
1546 copy_template(other_value
);
1551 HEXSTRING_ELEMENT
HEXSTRING_template::operator[](int index_value
)
1553 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
1554 TTCN_error("Accessing a hexstring element of a non-specific hexstring "
1556 return single_value
[index_value
];
1559 HEXSTRING_ELEMENT
HEXSTRING_template::operator[](const INTEGER
& index_value
)
1561 index_value
.must_bound("Indexing a hexstring template with an unbound "
1563 return (*this)[(int)index_value
];
1566 const HEXSTRING_ELEMENT
HEXSTRING_template::operator[](int index_value
) const
1568 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
1569 TTCN_error("Accessing a hexstring element of a non-specific hexstring "
1571 return single_value
[index_value
];
1574 const HEXSTRING_ELEMENT
HEXSTRING_template::operator[](const INTEGER
& index_value
) const
1576 index_value
.must_bound("Indexing a hexstring template with an unbound "
1578 return (*this)[(int)index_value
];
1581 boolean
HEXSTRING_template::match(const HEXSTRING
& other_value
,
1582 boolean
/* legacy */) const
1584 if (!other_value
.is_bound()) return FALSE
;
1585 if (!match_length(other_value
.val_ptr
->n_nibbles
)) return FALSE
;
1586 switch (template_selection
) {
1587 case SPECIFIC_VALUE
:
1588 return single_value
== other_value
;
1595 case COMPLEMENTED_LIST
:
1596 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1597 if (value_list
.list_value
[i
].match(other_value
)) return template_selection
1599 return template_selection
== COMPLEMENTED_LIST
;
1600 case STRING_PATTERN
:
1601 return match_pattern(pattern_value
, other_value
.val_ptr
);
1602 case DECODE_MATCH
: {
1603 TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL
, TTCN_EncDec::EB_WARNING
);
1604 TTCN_EncDec::clear_error();
1605 OCTETSTRING
os(hex2oct(other_value
));
1606 TTCN_Buffer
buff(os
);
1607 boolean ret_val
= dec_match
->instance
->match(buff
);
1608 TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL
,TTCN_EncDec::EB_DEFAULT
);
1609 TTCN_EncDec::clear_error();
1612 TTCN_error("Matching an uninitialized/unsupported hexstring template.");
1617 const HEXSTRING
& HEXSTRING_template::valueof() const
1619 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
) TTCN_error(
1620 "Performing a valueof or send operation on a non-specific "
1621 "hexstring template.");
1622 return single_value
;
1625 int HEXSTRING_template::lengthof() const
1628 boolean has_any_or_none
;
1629 if (is_ifpresent
) TTCN_error(
1630 "Performing lengthof() operation on a hexstring template "
1631 "which has an ifpresent attribute.");
1632 switch (template_selection
) {
1633 case SPECIFIC_VALUE
:
1634 min_length
= single_value
.lengthof();
1635 has_any_or_none
= FALSE
;
1638 TTCN_error("Performing lengthof() operation on a hexstring template "
1639 "containing omit value.");
1643 has_any_or_none
= TRUE
; // max. length is infinity
1646 // error if any element does not have length or the lengths differ
1647 if (value_list
.n_values
< 1) TTCN_error("Internal error: "
1648 "Performing lengthof() operation on a hexstring template "
1649 "containing an empty list.");
1650 int item_length
= value_list
.list_value
[0].lengthof();
1651 for (unsigned int i
= 1; i
< value_list
.n_values
; i
++) {
1652 if (value_list
.list_value
[i
].lengthof() != item_length
) TTCN_error(
1653 "Performing lengthof() operation on a hexstring template "
1654 "containing a value list with different lengths.");
1656 min_length
= item_length
;
1657 has_any_or_none
= FALSE
;
1660 case COMPLEMENTED_LIST
:
1661 TTCN_error("Performing lengthof() operation on a hexstring template "
1662 "containing complemented list.");
1663 case STRING_PATTERN
:
1665 has_any_or_none
= FALSE
; // TRUE if * chars in the pattern
1666 for (unsigned int i
= 0; i
< pattern_value
->n_elements
; i
++) {
1667 if (pattern_value
->elements_ptr
[i
] < 17)
1668 min_length
++; // case of 0-F, ?
1670 has_any_or_none
= TRUE
; // case of * character
1674 TTCN_error("Performing lengthof() operation on an "
1675 "uninitialized/unsupported hexstring template.");
1677 return check_section_is_single(min_length
, has_any_or_none
, "length", "a",
1678 "hexstring template");
1681 void HEXSTRING_template::set_type(template_sel template_type
,
1682 unsigned int list_length
)
1684 if (template_type
!= VALUE_LIST
&& template_type
!= COMPLEMENTED_LIST
&&
1685 template_type
!= DECODE_MATCH
) TTCN_error(
1686 "Setting an invalid list type for a hexstring template.");
1688 set_selection(template_type
);
1689 if (template_type
!= DECODE_MATCH
) {
1690 value_list
.n_values
= list_length
;
1691 value_list
.list_value
= new HEXSTRING_template
[list_length
];
1695 HEXSTRING_template
& HEXSTRING_template::list_item(unsigned int list_index
)
1697 if (template_selection
!= VALUE_LIST
&& template_selection
1698 != COMPLEMENTED_LIST
) TTCN_error(
1699 "Accessing a list element of a non-list hexstring template.");
1700 if (list_index
>= value_list
.n_values
) TTCN_error(
1701 "Index overflow in a hexstring value list template.");
1702 return value_list
.list_value
[list_index
];
1705 void HEXSTRING_template::set_decmatch(Dec_Match_Interface
* new_instance
)
1707 if (template_selection
!= DECODE_MATCH
) {
1708 TTCN_error("Setting the decoded content matching mechanism of a non-decmatch "
1709 "hexstring template.");
1711 dec_match
= new decmatch_struct
;
1712 dec_match
->ref_count
= 1;
1713 dec_match
->instance
= new_instance
;
1716 void HEXSTRING_template::log() const
1718 switch (template_selection
) {
1719 case SPECIFIC_VALUE
:
1722 case COMPLEMENTED_LIST
:
1723 TTCN_Logger::log_event_str("complement ");
1726 TTCN_Logger::log_char('(');
1727 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++) {
1728 if (i
> 0) TTCN_Logger::log_event_str(", ");
1729 value_list
.list_value
[i
].log();
1731 TTCN_Logger::log_char(')');
1733 case STRING_PATTERN
:
1734 TTCN_Logger::log_char('\'');
1735 for (unsigned int i
= 0; i
< pattern_value
->n_elements
; i
++) {
1736 unsigned char pattern
= pattern_value
->elements_ptr
[i
];
1738 TTCN_Logger::log_hex(pattern
);
1739 else if (pattern
== 16)
1740 TTCN_Logger::log_char('?');
1741 else if (pattern
== 17)
1742 TTCN_Logger::log_char('*');
1744 TTCN_Logger::log_event_str("<unknown>");
1746 TTCN_Logger::log_event_str("'H");
1749 TTCN_Logger::log_event_str("decmatch ");
1750 dec_match
->instance
->log();
1760 void HEXSTRING_template::log_match(const HEXSTRING
& match_value
,
1761 boolean
/* legacy */) const
1763 if (TTCN_Logger::VERBOSITY_COMPACT
== TTCN_Logger::get_matching_verbosity()
1764 && TTCN_Logger::get_logmatch_buffer_len() != 0) {
1765 TTCN_Logger::print_logmatch_buffer();
1766 TTCN_Logger::log_event_str(" := ");
1769 TTCN_Logger::log_event_str(" with ");
1771 if (match(match_value
))
1772 TTCN_Logger::log_event_str(" matched");
1774 TTCN_Logger::log_event_str(" unmatched");
1777 void HEXSTRING_template::set_param(Module_Param
& param
) {
1778 param
.basic_check(Module_Param::BC_TEMPLATE
|Module_Param::BC_LIST
, "hexstring template");
1779 Module_Param_Ptr mp
= ¶m
;
1780 if (param
.get_type() == Module_Param::MP_Reference
) {
1781 mp
= param
.get_referenced_param();
1783 switch (mp
->get_type()) {
1784 case Module_Param::MP_Omit
:
1787 case Module_Param::MP_Any
:
1790 case Module_Param::MP_AnyOrNone
:
1791 *this = ANY_OR_OMIT
;
1793 case Module_Param::MP_List_Template
:
1794 case Module_Param::MP_ComplementList_Template
: {
1795 HEXSTRING_template temp
;
1796 temp
.set_type(mp
->get_type() == Module_Param::MP_List_Template
?
1797 VALUE_LIST
: COMPLEMENTED_LIST
, mp
->get_size());
1798 for (size_t i
=0; i
<mp
->get_size(); i
++) {
1799 temp
.list_item(i
).set_param(*mp
->get_elem(i
));
1803 case Module_Param::MP_Hexstring
:
1804 *this = HEXSTRING(mp
->get_string_size(), (unsigned char*)mp
->get_string_data());
1806 case Module_Param::MP_Hexstring_Template
:
1807 *this = HEXSTRING_template(mp
->get_string_size(), (unsigned char*)mp
->get_string_data());
1809 case Module_Param::MP_Expression
:
1810 if (mp
->get_expr_type() == Module_Param::EXPR_CONCATENATE
) {
1811 HEXSTRING operand1
, operand2
;
1812 operand1
.set_param(*mp
->get_operand1());
1813 operand2
.set_param(*mp
->get_operand2());
1814 *this = operand1
+ operand2
;
1817 param
.expr_type_error("a bitstring");
1821 param
.type_error("hexstring template");
1823 is_ifpresent
= param
.get_ifpresent() || mp
->get_ifpresent();
1824 if (param
.get_length_restriction() != NULL
) {
1825 set_length_range(param
);
1828 set_length_range(*mp
);
1832 Module_Param
* HEXSTRING_template::get_param(Module_Param_Name
& param_name
) const
1834 Module_Param
* mp
= NULL
;
1835 switch (template_selection
) {
1836 case UNINITIALIZED_TEMPLATE
:
1837 mp
= new Module_Param_Unbound();
1840 mp
= new Module_Param_Omit();
1843 mp
= new Module_Param_Any();
1846 mp
= new Module_Param_AnyOrNone();
1848 case SPECIFIC_VALUE
:
1849 mp
= single_value
.get_param(param_name
);
1852 case COMPLEMENTED_LIST
: {
1853 if (template_selection
== VALUE_LIST
) {
1854 mp
= new Module_Param_List_Template();
1857 mp
= new Module_Param_ComplementList_Template();
1859 for (size_t i
= 0; i
< value_list
.n_values
; ++i
) {
1860 mp
->add_elem(value_list
.list_value
[i
].get_param(param_name
));
1863 case STRING_PATTERN
: {
1864 unsigned char* val_cpy
= (unsigned char*)Malloc(pattern_value
->n_elements
);
1865 memcpy(val_cpy
, pattern_value
->elements_ptr
, pattern_value
->n_elements
);
1866 mp
= new Module_Param_Hexstring_Template(pattern_value
->n_elements
, val_cpy
);
1869 mp
->error("Referencing a decoded content matching template is not supported.");
1875 mp
->set_ifpresent();
1877 mp
->set_length_restriction(get_length_range());
1881 void HEXSTRING_template::encode_text(Text_Buf
& text_buf
) const
1883 encode_text_restricted(text_buf
);
1884 switch (template_selection
) {
1889 case SPECIFIC_VALUE
:
1890 single_value
.encode_text(text_buf
);
1893 case COMPLEMENTED_LIST
:
1894 text_buf
.push_int(value_list
.n_values
);
1895 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1896 value_list
.list_value
[i
].encode_text(text_buf
);
1898 case STRING_PATTERN
:
1899 text_buf
.push_int(pattern_value
->n_elements
);
1900 text_buf
.push_raw(pattern_value
->n_elements
, pattern_value
->elements_ptr
);
1903 TTCN_error("Text encoder: Encoding an uninitialized/unsupported "
1904 "hexstring template.");
1908 void HEXSTRING_template::decode_text(Text_Buf
& text_buf
)
1911 decode_text_restricted(text_buf
);
1912 switch (template_selection
) {
1917 case SPECIFIC_VALUE
:
1918 single_value
.decode_text(text_buf
);
1921 case COMPLEMENTED_LIST
:
1922 value_list
.n_values
= text_buf
.pull_int().get_val();
1923 value_list
.list_value
= new HEXSTRING_template
[value_list
.n_values
];
1924 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1925 value_list
.list_value
[i
].decode_text(text_buf
);
1927 case STRING_PATTERN
: {
1928 unsigned int n_elements
= text_buf
.pull_int().get_val();
1930 = (hexstring_pattern_struct
*) Malloc(sizeof(hexstring_pattern_struct
) + n_elements
- 1);
1931 pattern_value
->ref_count
= 1;
1932 pattern_value
->n_elements
= n_elements
;
1933 text_buf
.pull_raw(n_elements
, pattern_value
->elements_ptr
);
1937 TTCN_error("Text decoder: An unknown/unsupported selection was "
1938 "received for a hexstring template.");
1942 boolean
HEXSTRING_template::is_present(boolean legacy
/* = FALSE */) const
1944 if (template_selection
==UNINITIALIZED_TEMPLATE
) return FALSE
;
1945 return !match_omit(legacy
);
1948 boolean
HEXSTRING_template::match_omit(boolean legacy
/* = FALSE */) const
1950 if (is_ifpresent
) return TRUE
;
1951 switch (template_selection
) {
1956 case COMPLEMENTED_LIST
:
1958 // legacy behavior: 'omit' can appear in the value/complement list
1959 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1960 if (value_list
.list_value
[i
].match_omit()) return template_selection
1962 return template_selection
== COMPLEMENTED_LIST
;
1964 // else fall through
1971 #ifndef TITAN_RUNTIME_2
1972 void HEXSTRING_template::check_restriction(template_res t_res
, const char* t_name
,
1973 boolean legacy
/* = FALSE */) const
1975 if (template_selection
==UNINITIALIZED_TEMPLATE
) return;
1976 switch ((t_name
&&(t_res
==TR_VALUE
))?TR_OMIT
:t_res
) {
1978 if (!is_ifpresent
&& template_selection
==SPECIFIC_VALUE
) return;
1981 if (!is_ifpresent
&& (template_selection
==OMIT_VALUE
||
1982 template_selection
==SPECIFIC_VALUE
)) return;
1985 if (!match_omit(legacy
)) return;
1990 TTCN_error("Restriction `%s' on template of type %s violated.",
1991 get_res_name(t_res
), t_name
? t_name
: "hexstring");