1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 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
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "Charstring.hh"
9 #include "../common/memory.h"
10 #include "../common/pattern.hh"
12 #include "Octetstring.hh"
13 #include "String_struct.hh"
14 #include "Parameters.h"
15 #include "Param_Types.hh"
26 #include "../common/dbgnew.hh"
32 #define ERRMSG_BUFSIZE 500
34 /** The amount of memory needed for a string containing n characters.
35 * -sizeof(int) because that much is already in charstring_struct.
36 * +1 for the terminating null character. */
37 #define MEMORY_SIZE(n) (sizeof(charstring_struct) - sizeof(int) + 1 + (n))
39 /** Allocate the memory needed to hold n_chars characters.
41 * @param \p n_chars the number of characters to hold
42 * @pre \p n_chars must be >= 0
44 void CHARSTRING::init_struct(int n_chars
)
48 TTCN_error("Initializing a charstring with a negative length.");
49 } else if (n_chars
== 0) {
50 /** This will represent the empty strings so they won't need allocated
51 * memory, this delays the memory allocation until it is really needed.
53 static charstring_struct empty_string
= { 1, 0, "" };
54 val_ptr
= &empty_string
;
55 empty_string
.ref_count
++;
57 val_ptr
= (charstring_struct
*)Malloc(MEMORY_SIZE(n_chars
));
58 val_ptr
->ref_count
= 1;
59 val_ptr
->n_chars
= n_chars
;
60 val_ptr
->chars_ptr
[n_chars
] = '\0';
64 /** Implement the copy-on-write.
66 * Called from the various CHARSTRING_ELEMENT::operator=(), just before
67 * the string is about to be modified. Stops the sharing of the CHARSTRING
68 * and creates a new copy for modification.
70 void CHARSTRING::copy_value()
72 if (val_ptr
== NULL
|| val_ptr
->n_chars
<= 0)
73 TTCN_error("Internal error: Invalid internal data structure when copying "
74 "the memory area of a charstring value.");
75 if (val_ptr
->ref_count
> 1) {
76 charstring_struct
*old_ptr
= val_ptr
;
78 init_struct(old_ptr
->n_chars
);
79 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
+ 1);
83 /** Create an uninitialized CHARSTRING object.
85 * Called from CHARSTRING::operator+() to create the return value with
86 * enough storage to hold the concatenation of the arguments.
88 * @param n_chars the number of characters to hold
91 CHARSTRING::CHARSTRING(int n_chars
)
96 CHARSTRING::CHARSTRING()
101 CHARSTRING::CHARSTRING(char other_value
)
104 val_ptr
->chars_ptr
[0] = other_value
;
107 CHARSTRING::CHARSTRING(const char *chars_ptr
)
110 if (chars_ptr
!= NULL
) n_chars
= strlen(chars_ptr
);
112 init_struct(n_chars
);
113 memcpy(val_ptr
->chars_ptr
, chars_ptr
, n_chars
);
116 CHARSTRING::CHARSTRING(int n_chars
, const char *chars_ptr
)
118 init_struct(n_chars
);
119 memcpy(val_ptr
->chars_ptr
, chars_ptr
, n_chars
);
122 CHARSTRING::CHARSTRING(const CHARSTRING
& other_value
)
123 : Base_Type(other_value
), val_ptr(other_value
.val_ptr
)
125 other_value
.must_bound("Copying an unbound charstring value.");
126 // ref_count can only be incremented after we check val_ptr
127 val_ptr
->ref_count
++;
130 CHARSTRING::CHARSTRING(const CHARSTRING_ELEMENT
& other_value
)
132 other_value
.must_bound("Initialization of a charstring with an unbound "
133 "charstring element.");
135 val_ptr
->chars_ptr
[0] = other_value
.get_char();
138 CHARSTRING::~CHARSTRING()
143 void CHARSTRING::clean_up()
145 if (val_ptr
!= NULL
) {
146 if (val_ptr
->ref_count
> 1) val_ptr
->ref_count
--;
147 else if (val_ptr
->ref_count
== 1) Free(val_ptr
);
148 else TTCN_error("Internal error: Invalid reference counter in a charstring "
154 CHARSTRING
& CHARSTRING::operator=(const char* other_value
)
156 if (val_ptr
== NULL
|| val_ptr
->chars_ptr
!= other_value
) {
159 if (other_value
!= NULL
) n_chars
= strlen(other_value
);
161 init_struct(n_chars
);
162 memcpy(val_ptr
->chars_ptr
, other_value
, n_chars
);
167 CHARSTRING
& CHARSTRING::operator=(const CHARSTRING
& other_value
)
169 other_value
.must_bound("Assignment of an unbound charstring value.");
170 if (&other_value
!= this) {
172 val_ptr
= other_value
.val_ptr
;
173 val_ptr
->ref_count
++;
178 CHARSTRING
& CHARSTRING::operator=(const CHARSTRING_ELEMENT
& other_value
)
180 other_value
.must_bound("Assignment of an unbound charstring element to "
182 char char_value
= other_value
.get_char();
185 val_ptr
->chars_ptr
[0] = char_value
;
189 CHARSTRING
& CHARSTRING::operator=(const UNIVERSAL_CHARSTRING
& other_value
)
191 other_value
.must_bound("Assignment of an unbound universal charstring to "
194 int n_chars
= other_value
.val_ptr
->n_uchars
;
195 init_struct(n_chars
);
196 for (int i
= 0; i
< n_chars
; ++i
) {
197 const universal_char
& uc
= other_value
.val_ptr
->uchars_ptr
[i
];
198 if (uc
.uc_group
!= 0 || uc
.uc_plane
!= 0 || uc
.uc_row
!= 0) {
199 TTCN_error("Multiple-byte characters cannot be assigned to a charstring, "
200 "invalid character char(%u, %u, %u, %u) at index %d.",
201 uc
.uc_group
, uc
.uc_plane
, uc
.uc_row
, uc
.uc_cell
, i
);
203 val_ptr
->chars_ptr
[i
] = other_value
.val_ptr
->uchars_ptr
[i
].uc_cell
;
208 boolean
CHARSTRING::operator==(const char* other_value
) const
210 must_bound("Unbound operand of charstring comparison.");
211 if (other_value
== NULL
) other_value
= "";
212 return !strcmp(val_ptr
->chars_ptr
, other_value
);
215 boolean
CHARSTRING::operator==(const CHARSTRING
& other_value
) const
217 must_bound("Unbound operand of charstring comparison.");
218 other_value
.must_bound("Unbound operand of charstring comparison.");
219 if (val_ptr
->n_chars
!= other_value
.val_ptr
->n_chars
) return FALSE
;
220 else return !memcmp(val_ptr
->chars_ptr
, other_value
.val_ptr
->chars_ptr
,
224 boolean
CHARSTRING::operator==(const CHARSTRING_ELEMENT
& other_value
) const
226 other_value
.must_bound("Unbound operand of charstring element "
228 must_bound("Unbound operand of charstring comparison.");
229 if (val_ptr
->n_chars
!= 1) return FALSE
;
230 else return val_ptr
->chars_ptr
[0] == other_value
.get_char();
233 boolean
CHARSTRING::operator==(const UNIVERSAL_CHARSTRING
& other_value
) const
235 must_bound("The left operand of comparison is an unbound charstring value.");
236 other_value
.must_bound("The right operand of comparison is an unbound "
237 "universal charstring value.");
238 if (other_value
.charstring
)
239 return *this == other_value
.cstr
;
240 if (val_ptr
->n_chars
!= other_value
.val_ptr
->n_uchars
) return FALSE
;
241 for (int i
= 0; i
< val_ptr
->n_chars
; i
++) {
242 if (other_value
.val_ptr
->uchars_ptr
[i
].uc_group
!= 0 ||
243 other_value
.val_ptr
->uchars_ptr
[i
].uc_plane
!= 0 ||
244 other_value
.val_ptr
->uchars_ptr
[i
].uc_row
!= 0 ||
245 other_value
.val_ptr
->uchars_ptr
[i
].uc_cell
!= (cbyte
)val_ptr
->chars_ptr
[i
])
251 boolean
CHARSTRING::operator==(const UNIVERSAL_CHARSTRING_ELEMENT
& other_value
)
254 must_bound("The left operand of comparison is an unbound charstring value.");
255 other_value
.must_bound("The right operand of comparison is an unbound "
256 "universal charstring element.");
257 if (val_ptr
->n_chars
!= 1) return FALSE
;
258 const universal_char
& uchar
= other_value
.get_uchar();
259 return uchar
.uc_group
== 0 && uchar
.uc_plane
== 0 && uchar
.uc_row
== 0 &&
260 uchar
.uc_cell
== (cbyte
)val_ptr
->chars_ptr
[0];
263 CHARSTRING
CHARSTRING::operator+(const char* other_value
) const
265 must_bound("Unbound operand of charstring concatenation.");
267 if (other_value
== NULL
) other_len
= 0;
268 else other_len
= strlen(other_value
);
269 if (other_len
== 0) return *this;
270 CHARSTRING
ret_val(val_ptr
->n_chars
+ other_len
);
271 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, val_ptr
->n_chars
);
272 memcpy(ret_val
.val_ptr
->chars_ptr
+ val_ptr
->n_chars
, other_value
, other_len
);
276 CHARSTRING
CHARSTRING::operator+(const CHARSTRING
& other_value
) const
278 must_bound("Unbound operand of charstring concatenation.");
279 other_value
.must_bound("Unbound operand of charstring concatenation.");
280 int first_n_chars
= val_ptr
->n_chars
;
281 if (first_n_chars
== 0) return other_value
;
282 int second_n_chars
= other_value
.val_ptr
->n_chars
;
283 if (second_n_chars
== 0) return *this;
284 CHARSTRING
ret_val(first_n_chars
+ second_n_chars
);
285 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, first_n_chars
);
286 memcpy(ret_val
.val_ptr
->chars_ptr
+ first_n_chars
,
287 other_value
.val_ptr
->chars_ptr
, second_n_chars
);
291 CHARSTRING
CHARSTRING::operator+(const CHARSTRING_ELEMENT
& other_value
) const
293 must_bound("Unbound operand of charstring concatenation.");
294 other_value
.must_bound("Unbound operand of charstring element "
296 CHARSTRING
ret_val(val_ptr
->n_chars
+ 1);
297 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, val_ptr
->n_chars
);
298 ret_val
.val_ptr
->chars_ptr
[val_ptr
->n_chars
] = other_value
.get_char();
302 UNIVERSAL_CHARSTRING
CHARSTRING::operator+
303 (const UNIVERSAL_CHARSTRING
& other_value
) const
305 must_bound("The left operand of concatenation is an unbound charstring "
307 other_value
.must_bound("The right operand of concatenation is an unbound "
308 "universal charstring value.");
309 if (val_ptr
->n_chars
== 0) return other_value
;
310 if (other_value
.charstring
) {
311 UNIVERSAL_CHARSTRING
ret_val(val_ptr
->n_chars
+ other_value
.cstr
.val_ptr
->n_chars
, true);
312 memcpy(ret_val
.cstr
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, val_ptr
->n_chars
);
313 memcpy(ret_val
.cstr
.val_ptr
->chars_ptr
+ val_ptr
->n_chars
, other_value
.cstr
.val_ptr
->chars_ptr
, other_value
.cstr
.val_ptr
->n_chars
);
316 UNIVERSAL_CHARSTRING
ret_val(val_ptr
->n_chars
+
317 other_value
.val_ptr
->n_uchars
);
318 for (int i
= 0; i
< val_ptr
->n_chars
; i
++) {
319 ret_val
.val_ptr
->uchars_ptr
[i
].uc_group
= 0;
320 ret_val
.val_ptr
->uchars_ptr
[i
].uc_plane
= 0;
321 ret_val
.val_ptr
->uchars_ptr
[i
].uc_row
= 0;
322 ret_val
.val_ptr
->uchars_ptr
[i
].uc_cell
= val_ptr
->chars_ptr
[i
];
324 memcpy(ret_val
.val_ptr
->uchars_ptr
+ val_ptr
->n_chars
,
325 other_value
.val_ptr
->uchars_ptr
,
326 other_value
.val_ptr
->n_uchars
* sizeof(universal_char
));
331 UNIVERSAL_CHARSTRING
CHARSTRING::operator+
332 (const UNIVERSAL_CHARSTRING_ELEMENT
& other_value
) const
334 must_bound("The left operand of concatenation is an unbound charstring "
336 other_value
.must_bound("The right operand of concatenation is an unbound "
337 "universal charstring element.");
338 if (other_value
.str_val
.charstring
) {
339 UNIVERSAL_CHARSTRING
ret_val(val_ptr
->n_chars
+ 1, true);
340 memcpy(ret_val
.cstr
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, val_ptr
->n_chars
);
341 ret_val
.cstr
.val_ptr
->chars_ptr
[val_ptr
->n_chars
] = other_value
.str_val
.cstr
.val_ptr
->chars_ptr
[other_value
.uchar_pos
];
344 UNIVERSAL_CHARSTRING
ret_val(val_ptr
->n_chars
+ 1);
345 for (int i
= 0; i
< val_ptr
->n_chars
; i
++) {
346 ret_val
.val_ptr
->uchars_ptr
[i
].uc_group
= 0;
347 ret_val
.val_ptr
->uchars_ptr
[i
].uc_plane
= 0;
348 ret_val
.val_ptr
->uchars_ptr
[i
].uc_row
= 0;
349 ret_val
.val_ptr
->uchars_ptr
[i
].uc_cell
= val_ptr
->chars_ptr
[i
];
351 ret_val
.val_ptr
->uchars_ptr
[val_ptr
->n_chars
] = other_value
.get_uchar();
356 CHARSTRING
& CHARSTRING::operator+=(char other_value
)
358 must_bound("Appending a character to an unbound charstring value.");
359 if (val_ptr
->ref_count
> 1) {
360 charstring_struct
*old_ptr
= val_ptr
;
361 old_ptr
->ref_count
--;
362 init_struct(old_ptr
->n_chars
+ 1);
363 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
);
364 val_ptr
->chars_ptr
[old_ptr
->n_chars
] = other_value
;
366 val_ptr
= (charstring_struct
*)
367 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ 1));
368 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = other_value
;
370 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
375 CHARSTRING
& CHARSTRING::operator+=(const char *other_value
)
377 must_bound("Appending a string literal to an unbound charstring value.");
378 if (other_value
!= NULL
) {
379 int other_n_chars
= strlen(other_value
);
380 if (other_n_chars
> 0) {
381 if (val_ptr
->ref_count
> 1) {
382 charstring_struct
*old_ptr
= val_ptr
;
383 old_ptr
->ref_count
--;
384 init_struct(old_ptr
->n_chars
+ other_n_chars
);
385 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
);
386 memcpy(val_ptr
->chars_ptr
+ old_ptr
->n_chars
, other_value
,
389 if (other_value
>= val_ptr
->chars_ptr
&&
390 other_value
<= val_ptr
->chars_ptr
+ val_ptr
->n_chars
) {
391 int offset
= other_value
- val_ptr
->chars_ptr
;
392 val_ptr
= (charstring_struct
*)
393 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ other_n_chars
));
394 memcpy(val_ptr
->chars_ptr
+ val_ptr
->n_chars
,
395 val_ptr
->chars_ptr
+ offset
, other_n_chars
);
397 val_ptr
= (charstring_struct
*)
398 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ other_n_chars
));
399 memcpy(val_ptr
->chars_ptr
+ val_ptr
->n_chars
, other_value
,
402 val_ptr
->n_chars
+= other_n_chars
;
403 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
410 CHARSTRING
& CHARSTRING::operator+=(const CHARSTRING
& other_value
)
412 must_bound("Appending a charstring value to an unbound charstring value.");
413 other_value
.must_bound("Appending an unbound charstring value to another "
414 "charstring value.");
415 int other_n_chars
= other_value
.val_ptr
->n_chars
;
416 if (other_n_chars
> 0) {
417 if (val_ptr
->n_chars
== 0) {
419 val_ptr
= other_value
.val_ptr
;
420 val_ptr
->ref_count
++;
421 } else if (val_ptr
->ref_count
> 1) {
422 charstring_struct
*old_ptr
= val_ptr
;
423 old_ptr
->ref_count
--;
424 init_struct(old_ptr
->n_chars
+ other_n_chars
);
425 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
);
426 memcpy(val_ptr
->chars_ptr
+ old_ptr
->n_chars
,
427 other_value
.val_ptr
->chars_ptr
, other_n_chars
);
429 val_ptr
= (charstring_struct
*)
430 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ other_n_chars
));
431 memcpy(val_ptr
->chars_ptr
+ val_ptr
->n_chars
,
432 other_value
.val_ptr
->chars_ptr
, other_n_chars
);
433 val_ptr
->n_chars
+= other_n_chars
;
434 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
440 CHARSTRING
& CHARSTRING::operator+=(const CHARSTRING_ELEMENT
& other_value
)
442 must_bound("Appending a charstring element to an unbound charstring value.");
443 other_value
.must_bound("Appending an unbound charstring element to a "
444 "charstring value.");
445 if (val_ptr
->ref_count
> 1) {
446 charstring_struct
*old_ptr
= val_ptr
;
447 old_ptr
->ref_count
--;
448 init_struct(old_ptr
->n_chars
+ 1);
449 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
);
450 val_ptr
->chars_ptr
[old_ptr
->n_chars
] = other_value
.get_char();
452 val_ptr
= (charstring_struct
*)
453 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ 1));
454 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = other_value
.get_char();
456 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
461 CHARSTRING
CHARSTRING::operator<<=(int rotate_count
) const
463 must_bound("Unbound charstring operand of rotate left operator.");
464 if (val_ptr
->n_chars
== 0) return *this;
465 if (rotate_count
>= 0) {
466 rotate_count
%= val_ptr
->n_chars
;
467 if (rotate_count
== 0) return *this;
468 CHARSTRING
ret_val(val_ptr
->n_chars
);
469 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
+ rotate_count
,
470 val_ptr
->n_chars
- rotate_count
);
471 memcpy(ret_val
.val_ptr
->chars_ptr
+ val_ptr
->n_chars
- rotate_count
,
472 val_ptr
->chars_ptr
, rotate_count
);
474 } else return *this >>= (-rotate_count
);
477 CHARSTRING
CHARSTRING::operator<<=(const INTEGER
& rotate_count
) const
479 rotate_count
.must_bound("Unbound integer operand of rotate left "
481 return *this <<= (int)rotate_count
;
484 CHARSTRING
CHARSTRING::operator>>=(int rotate_count
) const
486 must_bound("Unbound charstring operand of rotate right operator.");
487 if (val_ptr
->n_chars
== 0) return *this;
488 if (rotate_count
>= 0) {
489 rotate_count
%= val_ptr
->n_chars
;
490 if (rotate_count
== 0) return *this;
491 CHARSTRING
ret_val(val_ptr
->n_chars
);
492 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
+ val_ptr
->n_chars
-
493 rotate_count
, rotate_count
);
494 memcpy(ret_val
.val_ptr
->chars_ptr
+ rotate_count
, val_ptr
->chars_ptr
,
495 val_ptr
->n_chars
- rotate_count
);
497 } else return *this <<= (-rotate_count
);
500 CHARSTRING
CHARSTRING::operator>>=(const INTEGER
& rotate_count
) const
502 rotate_count
.must_bound("Unbound integer operand of rotate right "
504 return *this >>= (int)rotate_count
;
507 CHARSTRING_ELEMENT
CHARSTRING::operator[](int index_value
)
509 if (val_ptr
== NULL
&& index_value
== 0) {
511 return CHARSTRING_ELEMENT(FALSE
, *this, 0);
513 must_bound("Accessing an element of an unbound charstring value.");
514 if (index_value
< 0) TTCN_error("Accessing a charstring element using a "
515 "negative index (%d).", index_value
);
516 int n_chars
= val_ptr
->n_chars
;
517 if (index_value
> n_chars
) TTCN_error("Index overflow when accessing a "
518 "charstring element: The index is %d, but the string has only %d "
519 "characters.", index_value
, n_chars
);
520 if (index_value
== n_chars
) {
521 if (val_ptr
->ref_count
== 1) {
522 val_ptr
= (charstring_struct
*)
523 Realloc(val_ptr
, MEMORY_SIZE(n_chars
+ 1));
525 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
527 charstring_struct
*old_ptr
= val_ptr
;
528 old_ptr
->ref_count
--;
529 init_struct(n_chars
+ 1);
530 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, n_chars
);
532 return CHARSTRING_ELEMENT(FALSE
, *this, index_value
);
533 } else return CHARSTRING_ELEMENT(TRUE
, *this, index_value
);
537 CHARSTRING_ELEMENT
CHARSTRING::operator[](const INTEGER
& index_value
)
539 index_value
.must_bound("Indexing a charstring value with an unbound integer "
541 return (*this)[(int)index_value
];
544 const CHARSTRING_ELEMENT
CHARSTRING::operator[](int index_value
) const
546 must_bound("Accessing an element of an unbound charstring value.");
547 if (index_value
< 0) TTCN_error("Accessing a charstring element using a "
548 "negative index (%d).", index_value
);
549 if (index_value
>= val_ptr
->n_chars
) TTCN_error("Index overflow when "
550 "accessing a charstring element: The index is %d, but the string has only "
551 "%d characters.", index_value
, val_ptr
->n_chars
);
552 return CHARSTRING_ELEMENT(TRUE
, const_cast<CHARSTRING
&>(*this), index_value
);
555 const CHARSTRING_ELEMENT
CHARSTRING::operator[](const INTEGER
& index_value
) const
557 index_value
.must_bound("Indexing a charstring value with an unbound integer "
559 return (*this)[(int)index_value
];
562 CHARSTRING::operator const char*() const
564 must_bound("Casting an unbound charstring value to const char*.");
565 return val_ptr
->chars_ptr
;
568 int CHARSTRING::lengthof() const
570 must_bound("Performing lengthof operation on an unbound charstring value.");
571 return val_ptr
->n_chars
;
574 void CHARSTRING::log() const
576 if (val_ptr
!= NULL
) {
577 expstring_t buffer
= 0;
578 enum { INIT
, PCHAR
, NPCHAR
} state
= INIT
;
579 for (int i
= 0; i
< val_ptr
->n_chars
; i
++) {
580 char c
= val_ptr
->chars_ptr
[i
];
581 if (TTCN_Logger::is_printable(c
)) {
582 // the actual character is printable
584 case NPCHAR
: // concatenation sign if previous part was not printable
585 buffer
= mputstr(buffer
, " & ");
587 case INIT
: // opening "
588 buffer
= mputc(buffer
, '"');
590 case PCHAR
: // the character itself
591 TTCN_Logger::log_char_escaped(c
, buffer
);
596 // the actual character is not printable
598 case PCHAR
: // closing " if previous part was printable
599 buffer
= mputc(buffer
, '"');
601 case NPCHAR
: // concatenation sign
602 buffer
= mputstr(buffer
, " & ");
604 case INIT
: // the character itself
605 buffer
= mputprintf(buffer
, "char(0, 0, 0, %u)", (unsigned char)c
);
613 case INIT
: // the string was empty
614 buffer
= mputstr(buffer
, "\"\"");
616 case PCHAR
: // last character was printable -> closing "
617 buffer
= mputc(buffer
, '"');
622 TTCN_Logger::log_event_str(buffer
);
625 TTCN_Logger::log_event_unbound();
629 void CHARSTRING::set_param(Module_Param
& param
) {
630 param
.basic_check(Module_Param::BC_VALUE
|Module_Param::BC_LIST
, "charstring value");
632 switch (param
.get_type()) {
633 case Module_Param::MP_Universal_Charstring
:
634 case Module_Param::MP_Charstring
:
635 switch (param
.get_operation_type()) {
636 case Module_Param::OT_ASSIGN
:
639 case Module_Param::OT_CONCAT
: {
640 // The universal charstring will decode the string value if it is UTF-8 encoded
641 UNIVERSAL_CHARSTRING ucs
;
642 ucs
.set_param(param
);
643 if (ucs
.charstring
) {
644 // No special characters were found
646 *this = *this + ucs
.cstr
;
651 // Special characters found -> check if the UTF-8 decoding resulted in any multi-byte characters
652 for (int i
= 0; i
< ucs
.val_ptr
->n_uchars
; ++i
) {
653 if (0 != ucs
.val_ptr
->uchars_ptr
[i
].uc_group
||
654 0 != ucs
.val_ptr
->uchars_ptr
[i
].uc_plane
||
655 0 != ucs
.val_ptr
->uchars_ptr
[i
].uc_row
) {
656 param
.error("Type mismatch: a charstring value without multi-octet characters was expected.");
659 CHARSTRING
new_cs(ucs
.val_ptr
->n_uchars
);
660 for (int i
= 0; i
< ucs
.val_ptr
->n_uchars
; ++i
) {
661 new_cs
.val_ptr
->chars_ptr
[i
] = ucs
.val_ptr
->uchars_ptr
[i
].uc_cell
;
664 *this = *this + new_cs
;
671 TTCN_error("Internal error: CHARSTRING::set_param()");
675 param
.type_error("charstring value");
679 void CHARSTRING::encode_text(Text_Buf
& text_buf
) const
681 must_bound("Text encoder: Encoding an unbound charstring value.");
682 int n_chars
= val_ptr
->n_chars
;
683 text_buf
.push_int(n_chars
);
684 if (n_chars
> 0) text_buf
.push_raw(n_chars
, val_ptr
->chars_ptr
);
687 void CHARSTRING::decode_text(Text_Buf
& text_buf
)
689 int n_chars
= text_buf
.pull_int().get_val();
691 TTCN_error("Text decoder: invalid length of a charstring.");
693 init_struct(n_chars
);
694 if (n_chars
> 0) text_buf
.pull_raw(n_chars
, val_ptr
->chars_ptr
);
697 void CHARSTRING::encode(const TTCN_Typedescriptor_t
& p_td
,
699 TTCN_EncDec::coding_t p_coding
, ...) const
702 va_start(pvar
, p_coding
);
704 case TTCN_EncDec::CT_BER
: {
705 TTCN_EncDec_ErrorContext
ec("While BER-encoding type '%s': ", p_td
.name
);
706 unsigned BER_coding
=va_arg(pvar
, unsigned);
707 BER_encode_chk_coding(BER_coding
);
708 ASN_BER_TLV_t
*tlv
=BER_encode_TLV(p_td
, BER_coding
);
709 tlv
->put_in_buffer(p_buf
);
710 ASN_BER_TLV_t::destruct(tlv
);
712 case TTCN_EncDec::CT_RAW
: {
713 TTCN_EncDec_ErrorContext
ec("While RAW-encoding type '%s': ", p_td
.name
);
715 TTCN_EncDec_ErrorContext::error_internal
716 ("No RAW descriptor available for type '%s'.", p_td
.name
);
720 RAW_enc_tree
root(TRUE
,NULL
,&rp
,1,p_td
.raw
);
721 RAW_encode(p_td
, root
);
722 root
.put_to_buf(p_buf
);
724 case TTCN_EncDec::CT_TEXT
: {
725 TTCN_EncDec_ErrorContext
ec("While TEXT-encoding type '%s': ", p_td
.name
);
727 TTCN_EncDec_ErrorContext::error_internal
728 ("No TEXT descriptor available for type '%s'.", p_td
.name
);
729 TEXT_encode(p_td
,p_buf
);
731 case TTCN_EncDec::CT_XER
: {
732 TTCN_EncDec_ErrorContext
ec("While XER-encoding type '%s': ", p_td
.name
);
733 unsigned XER_coding
=va_arg(pvar
, unsigned);
734 XER_encode(*p_td
.xer
, p_buf
, XER_coding
, 0, 0);
737 case TTCN_EncDec::CT_JSON
: {
738 TTCN_EncDec_ErrorContext
ec("While JSON-encoding type '%s': ", p_td
.name
);
740 TTCN_EncDec_ErrorContext::error_internal
741 ("No JSON descriptor available for type '%s'.", p_td
.name
);
742 JSON_Tokenizer
tok(va_arg(pvar
, int) != 0);
743 JSON_encode(p_td
, tok
);
744 p_buf
.put_s(tok
.get_buffer_length(), (const unsigned char*)tok
.get_buffer());
747 TTCN_error("Unknown coding method requested to encode type '%s'",
753 void CHARSTRING::decode(const TTCN_Typedescriptor_t
& p_td
,
755 TTCN_EncDec::coding_t p_coding
, ...)
758 va_start(pvar
, p_coding
);
760 case TTCN_EncDec::CT_BER
: {
761 TTCN_EncDec_ErrorContext
ec("While BER-decoding type '%s': ", p_td
.name
);
762 unsigned L_form
=va_arg(pvar
, unsigned);
764 BER_decode_str2TLV(p_buf
, tlv
, L_form
);
765 BER_decode_TLV(p_td
, tlv
, L_form
);
766 if(tlv
.isComplete
) p_buf
.increase_pos(tlv
.get_len());
768 case TTCN_EncDec::CT_RAW
: {
769 TTCN_EncDec_ErrorContext
ec("While RAW-decoding type '%s': ", p_td
.name
);
771 TTCN_EncDec_ErrorContext::error_internal
772 ("No RAW descriptor available for type '%s'.", p_td
.name
);
774 switch(p_td
.raw
->top_bit_order
){
782 if(RAW_decode(p_td
, p_buf
, p_buf
.get_len()*8, order
)<0)
783 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
784 "Can not decode type '%s', because invalid or incomplete"
785 " message was received"
788 case TTCN_EncDec::CT_TEXT
: {
789 Limit_Token_List limit
;
790 TTCN_EncDec_ErrorContext
ec("While TEXT-decoding type '%s': ", p_td
.name
);
792 TTCN_EncDec_ErrorContext::error_internal
793 ("No TEXT descriptor available for type '%s'.", p_td
.name
);
794 const unsigned char *b
=p_buf
.get_data();
795 if(b
[p_buf
.get_len()-1]!='\0'){
796 p_buf
.set_pos(p_buf
.get_len());
797 p_buf
.put_zero(8,ORDER_LSB
);
800 if(TEXT_decode(p_td
,p_buf
,limit
)<0)
801 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
802 "Can not decode type '%s', because invalid or incomplete"
803 " message was received"
806 case TTCN_EncDec::CT_XER
: {
807 TTCN_EncDec_ErrorContext
ec("While XER-decoding type '%s': ", p_td
.name
);
808 unsigned XER_coding
=va_arg(pvar
, unsigned);
809 XmlReaderWrap
reader(p_buf
);
810 int success
= reader
.Read();
811 for (; success
==1; success
=reader
.Read()) {
812 int type
= reader
.NodeType();
813 if (type
==XML_READER_TYPE_ELEMENT
)
816 XER_decode(*p_td
.xer
, reader
, XER_coding
, 0);
817 size_t bytes
= reader
.ByteConsumed();
818 p_buf
.set_pos(bytes
);
820 case TTCN_EncDec::CT_JSON
: {
821 TTCN_EncDec_ErrorContext
ec("While JSON-decoding type '%s': ", p_td
.name
);
823 TTCN_EncDec_ErrorContext::error_internal
824 ("No JSON descriptor available for type '%s'.", p_td
.name
);
825 JSON_Tokenizer
tok((const char*)p_buf
.get_data(), p_buf
.get_len());
826 if(JSON_decode(p_td
, tok
, false)<0)
827 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
828 "Can not decode type '%s', because invalid or incomplete"
829 " message was received"
831 p_buf
.set_pos(tok
.get_buf_pos());
834 TTCN_error("Unknown coding method requested to decode type '%s'",
841 CHARSTRING::BER_encode_TLV(const TTCN_Typedescriptor_t
& p_td
,
842 unsigned p_coding
) const
845 ASN_BER_TLV_t
*new_tlv
=BER_encode_chk_bound(is_bound());
847 new_tlv
=BER_encode_TLV_OCTETSTRING
848 (p_coding
, val_ptr
->n_chars
,
849 (const unsigned char*)val_ptr
->chars_ptr
);
851 new_tlv
=ASN_BER_V2TLV(new_tlv
, p_td
, p_coding
);
855 boolean
CHARSTRING::BER_decode_TLV(const TTCN_Typedescriptor_t
& p_td
,
856 const ASN_BER_TLV_t
& p_tlv
,
861 ASN_BER_TLV_t stripped_tlv
;
862 BER_decode_strip_tags(*p_td
.ber
, p_tlv
, L_form
, stripped_tlv
);
863 TTCN_EncDec_ErrorContext
ec("While decoding CHARSTRING type: ");
864 /* Upper estimation for the length. */
865 size_t stripped_tlv_len
= stripped_tlv
.get_len();
866 if (stripped_tlv_len
< 2) return FALSE
;
867 int max_len
= stripped_tlv_len
- 2;
868 init_struct(max_len
);
869 unsigned int octetnum_start
= 0;
870 BER_decode_TLV_OCTETSTRING(stripped_tlv
, L_form
, octetnum_start
,
872 (unsigned char*)val_ptr
->chars_ptr
);
873 if (val_ptr
->n_chars
< max_len
) {
874 if (val_ptr
->n_chars
== 0) {
878 val_ptr
= (charstring_struct
*)
879 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
));
880 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
886 int CHARSTRING::TEXT_decode(const TTCN_Typedescriptor_t
& p_td
,
887 TTCN_Buffer
& buff
, Limit_Token_List
& limit
, boolean no_err
, boolean
/*first_call*/)
889 int decoded_length
= 0;
892 if (p_td
.text
->begin_decode
) {
894 if ((tl
= p_td
.text
->begin_decode
->match_begin(buff
)) < 0) {
895 if (no_err
) return -1;
896 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR
,
897 "The specified token '%s' not found for '%s': ",
898 (const char*) *(p_td
.text
->begin_decode
), p_td
.name
);
901 decoded_length
+= tl
;
902 buff
.increase_pos(tl
);
904 // never return "not enough bits"
905 // if(buff.get_read_len()<=1 && no_err) return -TTCN_EncDec::ET_LEN_ERR;
907 if (p_td
.text
->select_token
) {
909 if ((tl
= p_td
.text
->select_token
->match_begin(buff
)) < 0) {
910 if (no_err
) return -1;
915 else if ( p_td
.text
->val
.parameters
916 && p_td
.text
->val
.parameters
->decoding_params
.min_length
!= -1) {
917 str_len
= p_td
.text
->val
.parameters
->decoding_params
.min_length
;
919 else if (p_td
.text
->end_decode
) {
921 if ((tl
= p_td
.text
->end_decode
->match_first(buff
)) < 0) {
922 if (no_err
) return -1;
927 else if (limit
.has_token()) {
929 if ((tl
= limit
.match(buff
)) < 0) tl
= buff
.get_read_len() - 1;
933 str_len
= buff
.get_read_len() - 1;
936 init_struct(str_len
);
937 memcpy(val_ptr
->chars_ptr
, buff
.get_read_data(), str_len
);
938 decoded_length
+= str_len
;
939 buff
.increase_pos(str_len
);
941 if ( p_td
.text
->val
.parameters
942 && p_td
.text
->val
.parameters
->decoding_params
.convert
!= 0) {
943 if (p_td
.text
->val
.parameters
->decoding_params
.convert
== 1) {
944 for (int a
= 0; a
< str_len
; a
++) {
945 val_ptr
->chars_ptr
[a
] = toupper(val_ptr
->chars_ptr
[a
]);
949 for (int a
= 0; a
< str_len
; a
++) {
950 val_ptr
->chars_ptr
[a
] = tolower(val_ptr
->chars_ptr
[a
]);
954 if (p_td
.text
->end_decode
) {
956 if ((tl
= p_td
.text
->end_decode
->match_begin(buff
)) < 0) {
957 if (no_err
) return -1;
958 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR
,
959 "The specified token '%s' not found for '%s': ",
960 (const char*) *(p_td
.text
->end_decode
), p_td
.name
);
963 decoded_length
+= tl
;
964 buff
.increase_pos(tl
);
966 return decoded_length
;
969 int CHARSTRING::TEXT_encode(const TTCN_Typedescriptor_t
& p_td
,
970 TTCN_Buffer
& buff
) const{
971 int encoded_length
=0;
972 if(p_td
.text
->begin_encode
){
973 buff
.put_cs(*p_td
.text
->begin_encode
);
974 encoded_length
+=p_td
.text
->begin_encode
->lengthof();
977 TTCN_EncDec_ErrorContext::error
978 (TTCN_EncDec::ET_UNBOUND
, "Encoding an unbound value.");
979 if(p_td
.text
->end_encode
){
980 buff
.put_cs(*p_td
.text
->end_encode
);
981 encoded_length
+=p_td
.text
->end_encode
->lengthof();
983 return encoded_length
;
986 if(p_td
.text
->val
.parameters
==NULL
){
988 encoded_length
+=val_ptr
->n_chars
;
992 if(val_ptr
->n_chars
<p_td
.text
->val
.parameters
->coding_params
.min_length
){
993 switch(p_td
.text
->val
.parameters
->coding_params
.just
){
995 chars_after
=p_td
.text
->
996 val
.parameters
->coding_params
.min_length
-val_ptr
->n_chars
;
1000 val
.parameters
->coding_params
.min_length
-val_ptr
->n_chars
;
1002 chars_before
=pad
-chars_after
;
1007 chars_before
=p_td
.text
->
1008 val
.parameters
->coding_params
.min_length
-val_ptr
->n_chars
;
1013 unsigned char* p
=NULL
;
1014 size_t len
=chars_before
;
1015 buff
.get_end(p
,len
);
1016 for(int a
=0;a
<chars_before
;a
++) p
[a
]=(unsigned char)' ';
1017 buff
.increase_length(chars_before
);
1018 encoded_length
+=chars_before
;
1021 switch(p_td
.text
->val
.parameters
->coding_params
.convert
){
1022 case -1:{ //lower_case
1023 unsigned char* p
=NULL
;
1024 size_t len
=val_ptr
->n_chars
;
1025 buff
.get_end(p
,len
);
1026 for(int a
=0;a
<val_ptr
->n_chars
;a
++)
1027 p
[a
]=(unsigned char)tolower(val_ptr
->chars_ptr
[a
]);
1028 buff
.increase_length(val_ptr
->n_chars
);
1031 case 0:{ // no conversion
1035 case 1: // upper_case
1038 unsigned char* p
=NULL
;
1039 size_t len
=val_ptr
->n_chars
;
1040 buff
.get_end(p
,len
);
1041 for(int a
=0;a
<val_ptr
->n_chars
;a
++)
1042 p
[a
]=(unsigned char)toupper(val_ptr
->chars_ptr
[a
]);
1043 buff
.increase_length(val_ptr
->n_chars
);
1047 encoded_length
+=val_ptr
->n_chars
;
1050 unsigned char* p
=NULL
;
1051 size_t len
=chars_after
;
1052 buff
.get_end(p
,len
);
1053 for(int a
=0;a
<chars_after
;a
++) p
[a
]=(unsigned char)' ';
1054 buff
.increase_length(chars_after
);
1055 encoded_length
+=chars_after
;
1060 if(p_td
.text
->end_encode
){
1061 buff
.put_cs(*p_td
.text
->end_encode
);
1062 encoded_length
+=p_td
.text
->end_encode
->lengthof();
1064 return encoded_length
;
1067 #ifdef TITAN_RUNTIME_2
1068 int CHARSTRING::encode_raw(TTCN_Buffer
& p_buf
) const
1070 p_buf
.put_string(*this);
1071 return val_ptr
? val_ptr
->n_chars
: 0;
1076 void xml_escape(const unsigned int masked_c
, TTCN_Buffer
& p_buf
)
1079 // length of the majority of the names of control characters, +3 for </>
1080 static const char *escapes
[32] = {
1081 "<nul/>","<soh/>","<stx/>","<etx/>","<eot/>","<enq/>","<ack/>","<bel/>",
1082 "<bs/>" ,"<tab/>","<lf/>" ,"<vt/>" ,"<ff/>" ,"<cr/>" ,"<so/>" ,"<si/>" ,
1083 "<dle/>","<dc1/>","<dc2/>","<dc3/>","<dc4/>","<nak/>","<syn/>","<etb/>",
1084 "<can/>","<em/>" ,"<sub/>","<esc/>","<is4/>","<is3/>","<is2/>","<is1/>",
1086 unsigned int c
= (masked_c
& 0x7FFFFFFF); // unmasked
1089 // XML's "own" characters, escaped according to X.680/2002, 11.15.4 b)
1091 p_buf
.put_s(4, (cbyte
*)"<");
1095 p_buf
.put_s(4, (cbyte
*)">");
1099 p_buf
.put_s(5, (cbyte
*)"&");
1102 // Control characters, escaped according to X.680/2002, 11.15.5
1103 case 8: case 11: case 12: case 14: case 15: case 25:
1104 // the name of these control characters has only two letters
1107 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
1108 case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23:
1109 case 24: case 26: case 27: case 28: case 29: case 30: case 31:
1110 // 9=TAB 10=LF 13=CR are absent from this block altogether
1111 p_buf
.put_s(len
, (cbyte
*)escapes
[c
]);
1114 case '\"': // HR58225
1115 p_buf
.put_s(6, (cbyte
*)""");
1118 case '\'': // X.693 20.3.13: Titan uses single quotes for attributes;
1119 // so if they appear in content they must be escaped.
1120 // Currently this happens even if the string is not an attribute.
1121 p_buf
.put_s(6, (cbyte
*)"'");
1124 case 9: case 10: case 13:
1125 c
= masked_c
; // put the mask back on (makes it >127)
1128 if (c
> 127) { // XML numeric entity, as in X.680/2002 11.15.8
1129 c
&= 0x7FFFFFFF; // take it off again
1130 // Ensure that an even number of hex digits is produced
1131 int width
= (1 + (c
> 0xFF) + (c
> 0xFFFF) + (c
> 0xFFFFFF)) << 1;
1133 len
= snprintf(escapade
, 16, "&#x%0*X;", width
, c
);
1134 p_buf
.put_s(len
, (cbyte
*)(escapade
+0));
1136 else { // a plain old, unmolested character
1143 // Base64 encoder table
1144 extern const char cb64
[]=
1145 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1147 int CHARSTRING::XER_encode(const XERdescriptor_t
& p_td
,
1148 TTCN_Buffer
& p_buf
, unsigned int flavor
, int indent
, embed_values_enc_struct_t
*) const
1151 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
1152 "Encoding an unbound character string value.");
1154 int exer
= is_exer(flavor
|= SIMPLE_TYPE
);
1155 // SIMPLE_TYPE has no influence on is_exer, we set it for later
1156 int encoded_length
=(int)p_buf
.get_len();
1157 bool do_empty_element
= val_ptr
==NULL
|| val_ptr
->n_chars
== 0;
1159 flavor
&= ~XER_RECOF
; // charstring doesn't care
1161 if (do_empty_element
&& exer
&& p_td
.dfeValue
!= 0) {
1162 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_REPR
,
1163 "An encoded value with DEFAULT-FOR-EMPTY instruction applied should not be empty");
1165 if (begin_xml(p_td
, p_buf
, flavor
, indent
, do_empty_element
) == -1) {
1166 --encoded_length
; // it was shortened by one
1169 if (!do_empty_element
) {
1170 const char * current
= val_ptr
->chars_ptr
;
1171 const char * const end
= val_ptr
->chars_ptr
+ val_ptr
->n_chars
;
1172 const char * to_escape
;
1174 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
1175 to_escape
= "<&>'\"\x09\x0A\x0D";
1176 mask
= 0x80000000; // guaranteed bigger than any Unicode character
1179 to_escape
= "<&>'\"";
1183 // If Base64 is needed, use a temporary buffer.
1184 TTCN_Buffer tmpbuf
, &rbuf
= (exer
&& (p_td
.xer_bits
& BASE_64
)) ? tmpbuf
: p_buf
;
1186 // This here is an optimization. Only <&> need to be escaped.
1187 // Contiguous runs of "ordinary" characters are put in the buffer
1188 // with a single call.
1189 // TODO: is it really faster ? strpbrk is probably O(nm)
1190 while ( const char * trouble
= strpbrk(current
, to_escape
) ) {
1191 rbuf
.put_s((size_t)(trouble
- current
), (cbyte
*)current
);
1192 xml_escape(*trouble
| mask
, rbuf
); // escape the troublesome character
1193 current
= trouble
+1;
1196 // put the remainder in the buffer
1197 rbuf
.put_s( (size_t)(end
- current
), (cbyte
*)current
);
1199 if (exer
&& (p_td
.xer_bits
& BASE_64
)) {
1200 size_t clear_len
= tmpbuf
.get_len(); // the length before padding
1201 // Pad the temporary buffer so i+1 and i+2 don't go outside the buffer
1202 unsigned char zero
[2] = {0,0};
1203 tmpbuf
.put_s(2, zero
);
1204 // Get the buffer after the possible realloc caused by the padding.
1205 cbyte
* in
= tmpbuf
.get_data();
1207 // Encode 3 bytes of cleartext into 4 bytes of Base64
1208 for (size_t i
= 0; i
< clear_len
; i
+= 3) {
1209 p_buf
.put_c( cb64
[ in
[i
] >> 2 ] );
1210 p_buf
.put_c( cb64
[ ((in
[i
] & 0x03) << 4) | ((in
[i
+1] & 0xf0) >> 4) ]);
1211 p_buf
.put_c( i
+1 < clear_len
1212 ? cb64
[ ((in
[i
+1] & 0x0f) << 2) | ((in
[i
+2] & 0xc0) >> 6) ]
1214 p_buf
.put_c( i
+2 < clear_len
? cb64
[ in
[i
+2] & 0x3f ] : '=' );
1219 end_xml(p_td
, p_buf
, flavor
, indent
, do_empty_element
);
1220 return (int)p_buf
.get_len() - encoded_length
;
1224 * Translates a Base64 value to either its 6-bit reconstruction value
1225 * or a negative number indicating some other meaning.
1226 * Public domain from http://iharder.net/base64 */
1227 char base64_decoder_table
[256] =
1229 -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
1230 -5,-5, // Whitespace: Tab and Linefeed
1231 -9,-9, // Decimal 11 - 12
1232 -5, // Whitespace: Carriage Return
1233 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
1234 -9,-9,-9,-9,-9, // Decimal 27 - 31
1235 -5, // Whitespace: Space
1236 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
1237 62, // Plus sign at decimal 43
1238 -9,-9,-9, // Decimal 44 - 46
1239 63, // Slash at decimal 47
1240 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
1241 -9,-9,-9, // Decimal 58 - 60
1242 -1, // Equals sign at decimal 61
1243 -9,-9,-9, // Decimal 62 - 64
1244 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
1245 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
1246 -9,-9,-9,-9,-9,-9, // Decimal 91 - 96
1247 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
1248 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
1249 -9,-9,-9,-9,-9 // Decimal 123 - 127
1250 ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
1251 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
1252 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
1253 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
1254 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
1255 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
1256 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
1257 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
1258 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
1259 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
1262 unsigned int xlate(cbyte
*in
, int phase
, unsigned char*dest
) {
1263 static unsigned char nbytes
[4] = { 3,1,1,2 };
1264 unsigned char out
[4];
1265 out
[0] = in
[0] << 2 | in
[1] >> 4;
1266 out
[1] = in
[1] << 4 | in
[2] >> 2;
1267 out
[2] = in
[2] << 6 | in
[3] >> 0;
1268 memcpy(dest
, out
, nbytes
[phase
]);
1269 return nbytes
[phase
];
1272 int CHARSTRING::XER_decode(const XERdescriptor_t
& p_td
, XmlReaderWrap
& reader
,
1273 unsigned int flavor
, embed_values_dec_struct_t
*) {
1274 int exer
= is_exer(flavor
);
1275 int success
= reader
.Ok(), depth
= -1;
1277 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
1278 const char * name
= verify_name(reader
, p_td
, exer
);
1280 const char * value
= (const char *)reader
.Value();
1281 // FIXME copy & paste
1284 // Let the caller do reader.AdvanceAttribute();
1287 bool omit_tag
= exer
1288 && (p_td
.xer_bits
& UNTAGGED
|| flavor
& (EMBED_VALUES
|XER_LIST
|USE_TYPE_ATTR
|USE_NIL
));
1289 for (; success
== 1; success
= reader
.Read()) {
1290 int type
= reader
.NodeType();
1291 if (XML_READER_TYPE_ELEMENT
== type
) {
1292 verify_name(reader
, p_td
, exer
);
1293 if (reader
.IsEmptyElement()) { // has no text, needs special processing
1294 if (exer
&& p_td
.dfeValue
!= 0) {
1295 *this = *static_cast<const CHARSTRING
*>(p_td
.dfeValue
);
1297 else init_struct(0);
1299 break; // exit the loop early
1300 } // if empty element
1301 // otherwise, not an empty element, stay in the loop
1302 depth
= reader
.Depth();
1304 else if ((depth
!= -1 || omit_tag
)
1305 && (XML_READER_TYPE_TEXT
== type
|| XML_READER_TYPE_CDATA
== type
))
1306 // Process #text node if we already processed the element node, or
1307 // there is no element node because UNTAGGED is in effect.
1309 const xmlChar
* value
= reader
.Value();
1310 size_t num_chars
= strlen((const char*)value
);
1312 if (exer
&& (p_td
.xer_bits
& BASE_64
)) {
1314 init_struct(num_chars
* 3 / 4);
1318 unsigned char * dest
= (unsigned char *)val_ptr
->chars_ptr
;
1320 for (size_t o
=0; o
<num_chars
; ++o
) {
1321 xmlChar c
= value
[o
];
1322 if(c
== '=') { // Padding starts; decode last chunk and exit.
1323 dest
+= xlate(in
,phase
, dest
);
1327 int val
= base64_decoder_table
[c
];
1330 phase
= (phase
+ 1) % 4;
1332 dest
+= xlate(in
,phase
, dest
);
1333 in
[0]=in
[1]=in
[2]=in
[3]=0;
1336 else if (exer
&& (flavor
& EXIT_ON_ERROR
)) {
1340 TTCN_EncDec_ErrorContext::warning(
1341 /* if this was an error... TTCN_EncDec::ET_INVAL_MSG,*/
1342 "Invalid character for Base64 '%02X'", c
);
1346 val_ptr
->n_chars
= (char*)dest
- val_ptr
->chars_ptr
;
1350 init_struct(num_chars
);
1351 memcpy(val_ptr
->chars_ptr
, value
, num_chars
);
1355 // find the end element
1356 for (success
= reader
.Read(); success
== 1; success
= reader
.Read()) {
1357 type
= reader
.NodeType();
1358 if (XML_READER_TYPE_END_ELEMENT
== type
) {
1359 verify_end(reader
, p_td
, depth
, exer
);
1360 reader
.Read(); // one last time
1367 else if (XML_READER_TYPE_END_ELEMENT
== type
) {
1369 verify_end(reader
, p_td
, depth
, exer
);
1371 // We are at our end tag and no content
1372 if (exer
&& p_td
.dfeValue
!= 0) {
1373 *this = *static_cast<const CHARSTRING
*>(p_td
.dfeValue
);
1375 else init_struct(0); // empty string
1384 if (exer
&& p_td
.whitespace
>= WHITESPACE_REPLACE
) { // includes _COLLAPSE
1385 for (int i
=0; i
<val_ptr
->n_chars
; ++i
) { // first, _REPLACE
1386 switch (val_ptr
->chars_ptr
[i
]) {
1387 case 9: // HORIZONTAL TAB
1388 case 10: // LINE FEED
1389 case 13: // CARRIAGE RETURN
1390 val_ptr
->chars_ptr
[i
] = ' ';
1397 if (p_td
.whitespace
>= WHITESPACE_COLLAPSE
) {
1399 const char *from
, *end
= val_ptr
->chars_ptr
+ val_ptr
->n_chars
;
1400 for (from
= to
= val_ptr
->chars_ptr
; from
< end
;) {
1402 // If the copied character (*to) was a space,
1403 // and the next character to be copied (*from) is also a space
1404 // (continuous run of spaces)
1405 // or this was the first character (leading spaces to be trimmed),
1406 // then don't advance the destination (will be overwritten).
1408 || (from
< end
&& *from
!= ' ' && to
> val_ptr
->chars_ptr
)) ++to
;
1411 val_ptr
->n_chars
= to
- val_ptr
->chars_ptr
; // truncate
1412 // TODO maybe realloc after truncation
1419 int CHARSTRING::RAW_encode(const TTCN_Typedescriptor_t
& p_td
,
1420 RAW_enc_tree
& myleaf
) const
1422 int bl
= val_ptr
->n_chars
* 8; // bit length
1423 int align_length
= p_td
.raw
->fieldlength
? p_td
.raw
->fieldlength
- bl
: 0;
1425 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
1426 "Encoding an unbound value.");
1428 if ((bl
+ align_length
) < val_ptr
->n_chars
* 8) {
1429 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
1430 "There is no sufficient bits to encode '%s': ", p_td
.name
);
1431 bl
= p_td
.raw
->fieldlength
;
1434 if (myleaf
.must_free
) Free(myleaf
.body
.leaf
.data_ptr
);
1435 myleaf
.must_free
= FALSE
;
1436 myleaf
.data_ptr_used
= TRUE
;
1437 myleaf
.body
.leaf
.data_ptr
= (unsigned char*) val_ptr
->chars_ptr
;
1438 if (p_td
.raw
->endianness
== ORDER_MSB
) myleaf
.align
= -align_length
;
1439 else myleaf
.align
= align_length
;
1440 return myleaf
.length
= bl
+ align_length
;
1443 int CHARSTRING::RAW_decode(const TTCN_Typedescriptor_t
& p_td
,
1444 TTCN_Buffer
& buff
, int limit
, raw_order_t top_bit_ord
, boolean no_err
,
1445 int /*sel_field*/, boolean
/*first_call*/)
1447 int prepaddlength
= buff
.increase_pos_padd(p_td
.raw
->prepadding
);
1448 limit
-= prepaddlength
;
1449 int decode_length
= p_td
.raw
->fieldlength
== 0
1450 ? (limit
/ 8) * 8 : p_td
.raw
->fieldlength
;
1451 if ( decode_length
> limit
1452 || decode_length
> (int) buff
.unread_len_bit()) {
1453 if (no_err
) return -TTCN_EncDec::ET_LEN_ERR
;
1454 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
1455 "There is not enough bits in the buffer to decode type %s.", p_td
.name
);
1456 decode_length
= ((limit
> (int) buff
.unread_len_bit() ? (int)buff
.unread_len_bit() : limit
) / 8) * 8;
1459 boolean orders
= FALSE
;
1460 if (p_td
.raw
->bitorderinoctet
== ORDER_MSB
) orders
= TRUE
;
1461 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
1462 cp
.bitorder
= orders
? ORDER_MSB
: ORDER_LSB
;
1464 if (p_td
.raw
->byteorder
== ORDER_MSB
) orders
= TRUE
;
1465 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
1466 cp
.byteorder
= orders
? ORDER_MSB
: ORDER_LSB
;
1467 cp
.fieldorder
= p_td
.raw
->fieldorder
;
1468 cp
.hexorder
= ORDER_LSB
;
1470 init_struct(decode_length
/ 8);
1471 buff
.get_b((size_t) decode_length
, (unsigned char*) val_ptr
->chars_ptr
, cp
,
1474 if (p_td
.raw
->length_restrition
!= -1) {
1475 val_ptr
->n_chars
= p_td
.raw
->length_restrition
;
1476 if (p_td
.raw
->endianness
== ORDER_MSB
) memmove(val_ptr
->chars_ptr
,
1477 val_ptr
->chars_ptr
+ (decode_length
/ 8 - val_ptr
->n_chars
),
1478 val_ptr
->n_chars
); // sizeof(char) == 1 by definition
1480 decode_length
+= buff
.increase_pos_padd(p_td
.raw
->padding
);
1481 return decode_length
+ prepaddlength
;
1484 char* CHARSTRING::to_JSON_string() const
1486 // Need at least 3 more characters (the double quotes around the string and the terminating zero)
1487 char* json_str
= (char*)Malloc(val_ptr
->n_chars
+ 3);
1490 json_str
= mputc(json_str
, '\"');
1492 for (int i
= 0; i
< val_ptr
->n_chars
; ++i
) {
1493 // Increase the size of the buffer if it's not big enough to store the
1494 // characters remaining in the charstring plus 1 (for safety, in case this
1495 // character needs to be double-escaped).
1496 switch(val_ptr
->chars_ptr
[i
]) {
1498 json_str
= mputstrn(json_str
, "\\\\", 2);
1501 json_str
= mputstrn(json_str
, "\\n", 2);
1504 json_str
= mputstrn(json_str
, "\\t", 2);
1507 json_str
= mputstrn(json_str
, "\\r", 2);
1510 json_str
= mputstrn(json_str
, "\\f", 2);
1513 json_str
= mputstrn(json_str
, "\\b", 2);
1516 json_str
= mputstrn(json_str
, "\\\"", 2);
1519 json_str
= mputc(json_str
, val_ptr
->chars_ptr
[i
]);
1524 json_str
= mputc(json_str
, '\"');
1528 boolean
CHARSTRING::from_JSON_string(const char* p_value
, size_t p_value_len
, boolean check_quotes
)
1531 size_t end
= p_value_len
;
1534 end
= p_value_len
- 1;
1535 if (p_value
[0] != '\"' || p_value
[p_value_len
- 1] != '\"') {
1540 // The charstring will be shorter than the JSON string, at least by the 2 quotes
1541 char* str
= (char*)Malloc(end
- start
);
1543 boolean error
= false;
1545 for (size_t i
= start
; i
< end
; ++i
) {
1546 if (0 > p_value
[i
]) {
1550 if ('\\' == p_value
[i
]) {
1555 switch(p_value
[i
+ 1]) {
1581 if (end
- i
>= 6 && '0' == p_value
[i
+ 2] && '0' == p_value
[i
+ 3]) {
1582 unsigned char upper_nibble
= char_to_hexdigit(p_value
[i
+ 4]);
1583 unsigned char lower_nibble
= char_to_hexdigit(p_value
[i
+ 5]);
1584 if (0x07 >= upper_nibble
&& 0x0F >= lower_nibble
) {
1585 str
[len
++] = (upper_nibble
<< 4) | lower_nibble
;
1586 // skip 4 extra characters (the 4 hex digits)
1589 // error (found something other than hex digits) -> leave the for cycle
1594 // error (not enough characters left or the first 2 hex digits are non-null) -> leave the for cycle
1601 // error (invalid escaped character) -> leave the for cycle
1606 // skip an extra character (the \)
1609 str
[len
++] = p_value
[i
];
1612 if (check_quotes
&& i
== p_value_len
- 1) {
1613 // Special case: the last 2 characters are double escaped quotes ('\\' and '\"')
1621 memcpy(val_ptr
->chars_ptr
, str
, len
);
1622 val_ptr
->chars_ptr
[len
] = 0;
1628 int CHARSTRING::JSON_encode(const TTCN_Typedescriptor_t
&, JSON_Tokenizer
& p_tok
) const
1631 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
1632 "Encoding an unbound charstring value.");
1636 char* tmp_str
= to_JSON_string();
1637 int enc_len
= p_tok
.put_next_token(JSON_TOKEN_STRING
, tmp_str
);
1642 int CHARSTRING::JSON_decode(const TTCN_Typedescriptor_t
& p_td
, JSON_Tokenizer
& p_tok
, boolean p_silent
)
1644 json_token_t token
= JSON_TOKEN_NONE
;
1646 size_t value_len
= 0;
1648 boolean use_default
= p_td
.json
->default_value
&& 0 == p_tok
.get_buffer_length();
1650 // No JSON data in the buffer -> use default value
1651 value
= (char*)p_td
.json
->default_value
;
1652 value_len
= strlen(value
);
1654 dec_len
= p_tok
.get_next_token(&token
, &value
, &value_len
);
1656 if (JSON_TOKEN_ERROR
== token
) {
1657 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_BAD_TOKEN_ERROR
, "");
1658 return JSON_ERROR_FATAL
;
1660 else if (JSON_TOKEN_STRING
== token
|| use_default
) {
1661 if (!from_JSON_string(value
, value_len
, !use_default
)) {
1662 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_FORMAT_ERROR
, "string", "charstring");
1664 return JSON_ERROR_FATAL
;
1667 return JSON_ERROR_INVALID_TOKEN
;
1673 CHARSTRING_ELEMENT::CHARSTRING_ELEMENT(boolean par_bound_flag
,
1674 CHARSTRING
& par_str_val
, int par_char_pos
)
1675 : bound_flag(par_bound_flag
), str_val(par_str_val
), char_pos(par_char_pos
)
1680 CHARSTRING_ELEMENT
& CHARSTRING_ELEMENT::operator=(const char* other_value
)
1682 if (other_value
== NULL
||
1683 other_value
[0] == '\0' || other_value
[1] != '\0')
1684 TTCN_error("Assignment of a charstring value with length other "
1685 "than 1 to a charstring element.");
1687 str_val
.copy_value();
1688 str_val
.val_ptr
->chars_ptr
[char_pos
] = other_value
[0];
1692 CHARSTRING_ELEMENT
& CHARSTRING_ELEMENT::operator=
1693 (const CHARSTRING
& other_value
)
1695 other_value
.must_bound("Assignment of an unbound charstring value to a "
1696 "charstring element.");
1697 if(other_value
.val_ptr
->n_chars
!= 1)
1698 TTCN_error("Assignment of a charstring value with length other than "
1699 "1 to a charstring element.");
1701 str_val
.copy_value();
1702 str_val
.val_ptr
->chars_ptr
[char_pos
] = other_value
.val_ptr
->chars_ptr
[0];
1706 CHARSTRING_ELEMENT
& CHARSTRING_ELEMENT::operator=
1707 (const CHARSTRING_ELEMENT
& other_value
)
1709 other_value
.must_bound("Assignment of an unbound charstring element.");
1710 if (&other_value
!= this) {
1712 str_val
.copy_value();
1713 str_val
.val_ptr
->chars_ptr
[char_pos
] =
1714 other_value
.str_val
.val_ptr
->chars_ptr
[other_value
.char_pos
];
1719 boolean
CHARSTRING_ELEMENT::operator==(const char *other_value
) const
1721 must_bound("Comparison of an unbound charstring element.");
1722 if (other_value
== NULL
|| other_value
[0] == '\0' ||
1723 other_value
[1] != '\0') return FALSE
;
1724 return str_val
.val_ptr
->chars_ptr
[char_pos
] == other_value
[0];
1727 boolean
CHARSTRING_ELEMENT::operator==(const CHARSTRING
& other_value
) const
1729 must_bound("Comparison of an unbound charstring element.");
1730 other_value
.must_bound("Comparison of an unbound charstring value.");
1731 if (other_value
.val_ptr
->n_chars
!= 1) return FALSE
;
1732 return str_val
.val_ptr
->chars_ptr
[char_pos
] ==
1733 other_value
.val_ptr
->chars_ptr
[0];
1736 boolean
CHARSTRING_ELEMENT::operator==(const CHARSTRING_ELEMENT
& other_value
) const
1738 must_bound("Comparison of an unbound charstring element.");
1739 other_value
.must_bound("Comparison of an unbound charstring element.");
1740 return str_val
.val_ptr
->chars_ptr
[char_pos
] ==
1741 other_value
.str_val
.val_ptr
->chars_ptr
[other_value
.char_pos
];
1744 boolean
CHARSTRING_ELEMENT::operator==(const UNIVERSAL_CHARSTRING
& other_value
)
1747 must_bound("The left operand of comparison is an unbound charstring "
1749 other_value
.must_bound("The right operand of comparison is an unbound "
1750 "universal charstring value.");
1751 if (other_value
.charstring
) {
1752 if (other_value
.cstr
.val_ptr
->n_chars
!= 1) return FALSE
;
1753 return str_val
.val_ptr
->chars_ptr
[char_pos
] ==
1754 other_value
.cstr
.val_ptr
->chars_ptr
[0];
1757 if (other_value
.val_ptr
->n_uchars
!= 1) return FALSE
;
1758 return other_value
.val_ptr
->uchars_ptr
[0].uc_group
== 0 &&
1759 other_value
.val_ptr
->uchars_ptr
[0].uc_plane
== 0 &&
1760 other_value
.val_ptr
->uchars_ptr
[0].uc_row
== 0 &&
1761 other_value
.val_ptr
->uchars_ptr
[0].uc_cell
==
1762 (cbyte
)str_val
.val_ptr
->chars_ptr
[char_pos
];
1766 boolean
CHARSTRING_ELEMENT::operator==
1767 (const UNIVERSAL_CHARSTRING_ELEMENT
& other_value
) const
1769 must_bound("The left operand of comparison is an unbound charstring "
1771 other_value
.must_bound("The right operand of comparison is an unbound "
1772 "universal charstring element.");
1773 const universal_char
& uchar
= other_value
.get_uchar();
1774 return uchar
.uc_group
== 0 && uchar
.uc_plane
== 0 && uchar
.uc_row
== 0 &&
1775 uchar
.uc_cell
== (cbyte
)str_val
.val_ptr
->chars_ptr
[char_pos
];
1778 CHARSTRING
CHARSTRING_ELEMENT::operator+(const char *other_value
) const
1780 must_bound("Unbound operand of charstring element concatenation.");
1782 if (other_value
== NULL
) other_len
= 0;
1783 else other_len
= strlen(other_value
);
1784 CHARSTRING
ret_val(other_len
+ 1);
1785 ret_val
.val_ptr
->chars_ptr
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1786 memcpy(ret_val
.val_ptr
->chars_ptr
+ 1, other_value
, other_len
);
1790 CHARSTRING
CHARSTRING_ELEMENT::operator+(const CHARSTRING
& other_value
) const
1792 must_bound("Unbound operand of charstring element concatenation.");
1793 other_value
.must_bound("Unbound operand of charstring concatenation.");
1794 int n_chars
= other_value
.val_ptr
->n_chars
;
1795 CHARSTRING
ret_val(n_chars
+ 1);
1796 ret_val
.val_ptr
->chars_ptr
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1797 memcpy(ret_val
.val_ptr
->chars_ptr
+ 1, other_value
.val_ptr
->chars_ptr
,
1802 CHARSTRING
CHARSTRING_ELEMENT::operator+(const CHARSTRING_ELEMENT
&
1805 must_bound("Unbound operand of charstring element concatenation.");
1806 other_value
.must_bound("Unbound operand of charstring element "
1809 result
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1810 result
[1] = other_value
.str_val
.val_ptr
->chars_ptr
[other_value
.char_pos
];
1811 return CHARSTRING(2, result
);
1814 UNIVERSAL_CHARSTRING
CHARSTRING_ELEMENT::operator+
1815 (const UNIVERSAL_CHARSTRING
& other_value
) const
1817 must_bound("The left operand of concatenation is an unbound charstring "
1819 other_value
.must_bound("The right operand of concatenation is an unbound "
1820 "universal charstring value.");
1821 if (other_value
.charstring
) {
1822 UNIVERSAL_CHARSTRING
ret_val(other_value
.cstr
.val_ptr
->n_chars
+ 1, true);
1823 ret_val
.cstr
.val_ptr
->chars_ptr
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1824 memcpy(ret_val
.cstr
.val_ptr
->chars_ptr
+ 1, other_value
.cstr
.val_ptr
->chars_ptr
, other_value
.cstr
.val_ptr
->n_chars
);
1827 UNIVERSAL_CHARSTRING
ret_val(other_value
.val_ptr
->n_uchars
+ 1);
1828 ret_val
.val_ptr
->uchars_ptr
[0].uc_group
= 0;
1829 ret_val
.val_ptr
->uchars_ptr
[0].uc_plane
= 0;
1830 ret_val
.val_ptr
->uchars_ptr
[0].uc_row
= 0;
1831 ret_val
.val_ptr
->uchars_ptr
[0].uc_cell
= str_val
.val_ptr
->chars_ptr
[char_pos
];
1832 memcpy(ret_val
.val_ptr
->uchars_ptr
+ 1, other_value
.val_ptr
->uchars_ptr
,
1833 other_value
.val_ptr
->n_uchars
* sizeof(universal_char
));
1838 UNIVERSAL_CHARSTRING
CHARSTRING_ELEMENT::operator+
1839 (const UNIVERSAL_CHARSTRING_ELEMENT
& other_value
) const
1841 must_bound("The left operand of concatenation is an unbound charstring "
1843 other_value
.must_bound("The right operand of concatenation is an unbound "
1844 "universal charstring element.");
1845 universal_char result
[2];
1846 result
[0].uc_group
= 0;
1847 result
[0].uc_plane
= 0;
1848 result
[0].uc_row
= 0;
1849 result
[0].uc_cell
= str_val
.val_ptr
->chars_ptr
[char_pos
];
1850 result
[1] = other_value
.get_uchar();
1851 return UNIVERSAL_CHARSTRING(2, result
);
1854 char CHARSTRING_ELEMENT::get_char() const
1856 return str_val
.val_ptr
->chars_ptr
[char_pos
];
1859 void CHARSTRING_ELEMENT::log() const
1862 char c
= str_val
.val_ptr
->chars_ptr
[char_pos
];
1863 if (TTCN_Logger::is_printable(c
)) {
1864 TTCN_Logger::log_char('"');
1865 TTCN_Logger::log_char_escaped(c
);
1866 TTCN_Logger::log_char('"');
1867 } else TTCN_Logger::log_event("char(0, 0, 0, %u)", (unsigned char)c
);
1868 } else TTCN_Logger::log_event_unbound();
1873 boolean
operator==(const char* string_value
, const CHARSTRING
& other_value
)
1875 other_value
.must_bound("Unbound operand of charstring comparison.");
1876 if (string_value
== NULL
) string_value
= "";
1877 return !strcmp(string_value
, other_value
.val_ptr
->chars_ptr
);
1880 boolean
operator==(const char* string_value
,
1881 const CHARSTRING_ELEMENT
& other_value
)
1883 other_value
.must_bound("Unbound operand of charstring element "
1885 if (string_value
== NULL
|| string_value
[0] == '\0' ||
1886 string_value
[1] != '\0') return FALSE
;
1887 return string_value
[0] == other_value
.get_char();
1890 CHARSTRING
operator+(const char* string_value
, const CHARSTRING
& other_value
)
1892 other_value
.must_bound("Unbound operand of charstring concatenation.");
1894 if (string_value
== NULL
) string_len
= 0;
1895 else string_len
= strlen(string_value
);
1896 if (string_len
== 0) return other_value
;
1897 CHARSTRING
ret_val(string_len
+ other_value
.val_ptr
->n_chars
);
1898 memcpy(ret_val
.val_ptr
->chars_ptr
, string_value
, string_len
);
1899 memcpy(ret_val
.val_ptr
->chars_ptr
+ string_len
,
1900 other_value
.val_ptr
->chars_ptr
, other_value
.val_ptr
->n_chars
);
1904 CHARSTRING
operator+(const char* string_value
,
1905 const CHARSTRING_ELEMENT
& other_value
)
1907 other_value
.must_bound("Unbound operand of charstring element "
1910 if (string_value
== NULL
) string_len
= 0;
1911 else string_len
= strlen(string_value
);
1912 if (string_len
== 0) return CHARSTRING(other_value
);
1913 CHARSTRING
ret_val(string_len
+ 1);
1914 memcpy(ret_val
.val_ptr
->chars_ptr
, string_value
, string_len
);
1915 ret_val
.val_ptr
->chars_ptr
[string_len
] = other_value
.get_char();
1919 CHARSTRING
operator<<=(const char *string_value
, const INTEGER
& rotate_count
)
1921 return CHARSTRING(string_value
) <<= rotate_count
;
1924 CHARSTRING
operator>>=(const char *string_value
, const INTEGER
& rotate_count
)
1926 return CHARSTRING(string_value
) >>= rotate_count
;
1929 // charstring template class
1931 void CHARSTRING_template::clean_up()
1933 switch(template_selection
) {
1935 case COMPLEMENTED_LIST
:
1936 delete [] value_list
.list_value
;
1938 case STRING_PATTERN
:
1939 if (pattern_value
.regexp_init
) regfree(&pattern_value
.posix_regexp
);
1944 template_selection
= UNINITIALIZED_TEMPLATE
;
1947 void CHARSTRING_template::copy_template(const CHARSTRING_template
& other_value
)
1949 switch (other_value
.template_selection
) {
1950 case STRING_PATTERN
:
1951 pattern_value
.regexp_init
= FALSE
;
1953 case SPECIFIC_VALUE
:
1954 single_value
= other_value
.single_value
;
1961 case COMPLEMENTED_LIST
:
1962 value_list
.n_values
= other_value
.value_list
.n_values
;
1963 value_list
.list_value
= new CHARSTRING_template
[value_list
.n_values
];
1964 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1965 value_list
.list_value
[i
].copy_template(
1966 other_value
.value_list
.list_value
[i
]);
1969 if (!other_value
.value_range
.min_is_set
) TTCN_error("The lower bound is "
1970 "not set when copying a charstring value range template.");
1971 if (!other_value
.value_range
.max_is_set
) TTCN_error("The upper bound is "
1972 "not set when copying a charstring value range template.");
1973 value_range
= other_value
.value_range
;
1976 TTCN_error("Copying an uninitialized/unsupported charstring template.");
1978 set_selection(other_value
);
1981 CHARSTRING_template::CHARSTRING_template()
1985 CHARSTRING_template::CHARSTRING_template(template_sel other_value
)
1986 : Restricted_Length_Template(other_value
)
1988 check_single_selection(other_value
);
1991 CHARSTRING_template::CHARSTRING_template(const CHARSTRING
& other_value
)
1992 : Restricted_Length_Template(SPECIFIC_VALUE
), single_value(other_value
)
1996 CHARSTRING_template::CHARSTRING_template(const CHARSTRING_ELEMENT
& other_value
)
1997 : Restricted_Length_Template(SPECIFIC_VALUE
), single_value(other_value
)
2001 CHARSTRING_template::CHARSTRING_template(const OPTIONAL
<CHARSTRING
>& other_value
)
2003 switch (other_value
.get_selection()) {
2004 case OPTIONAL_PRESENT
:
2005 set_selection(SPECIFIC_VALUE
);
2006 single_value
= (const CHARSTRING
&)other_value
;
2009 set_selection(OMIT_VALUE
);
2012 TTCN_error("Creating a charstring template from an unbound optional "
2017 CHARSTRING_template::CHARSTRING_template(template_sel p_sel
,
2018 const CHARSTRING
& p_str
)
2019 : Restricted_Length_Template(STRING_PATTERN
), single_value(p_str
)
2021 if(p_sel
!=STRING_PATTERN
)
2022 TTCN_error("Internal error: Initializing a charstring pattern template "
2023 "with invalid selection.");
2024 pattern_value
.regexp_init
=FALSE
;
2027 CHARSTRING_template::CHARSTRING_template(const CHARSTRING_template
& other_value
)
2028 : Restricted_Length_Template()
2030 copy_template(other_value
);
2033 CHARSTRING_template::~CHARSTRING_template()
2038 CHARSTRING_template
& CHARSTRING_template::operator=(template_sel other_value
)
2040 check_single_selection(other_value
);
2042 set_selection(other_value
);
2046 CHARSTRING_template
& CHARSTRING_template::operator=
2047 (const CHARSTRING
& other_value
)
2049 other_value
.must_bound("Assignment of an unbound charstring value to a "
2052 set_selection(SPECIFIC_VALUE
);
2053 single_value
= other_value
;
2057 CHARSTRING_template
& CHARSTRING_template::operator=
2058 (const CHARSTRING_ELEMENT
& other_value
)
2060 other_value
.must_bound("Assignment of an unbound charstring element to a "
2063 set_selection(SPECIFIC_VALUE
);
2064 single_value
= other_value
;
2068 CHARSTRING_template
& CHARSTRING_template::operator=
2069 (const OPTIONAL
<CHARSTRING
>& other_value
)
2072 switch (other_value
.get_selection()) {
2073 case OPTIONAL_PRESENT
:
2074 set_selection(SPECIFIC_VALUE
);
2075 single_value
= (const CHARSTRING
&)other_value
;
2078 set_selection(OMIT_VALUE
);
2081 TTCN_error("Assignment of an unbound optional field to a charstring "
2087 CHARSTRING_template
& CHARSTRING_template::operator=
2088 (const CHARSTRING_template
& other_value
)
2090 if (&other_value
!= this) {
2092 copy_template(other_value
);
2097 CHARSTRING_ELEMENT
CHARSTRING_template::operator[](int index_value
)
2099 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
2100 TTCN_error("Accessing a charstring element of a non-specific charstring "
2102 return single_value
[index_value
];
2105 CHARSTRING_ELEMENT
CHARSTRING_template::operator[](const INTEGER
& index_value
)
2107 index_value
.must_bound("Indexing a charstring template with an unbound "
2109 return (*this)[(int)index_value
];
2112 const CHARSTRING_ELEMENT
CHARSTRING_template::operator[](int index_value
) const
2114 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
2115 TTCN_error("Accessing a charstring element of a non-specific charstring "
2117 return single_value
[index_value
];
2120 const CHARSTRING_ELEMENT
CHARSTRING_template::operator[](const INTEGER
& index_value
) const
2122 index_value
.must_bound("Indexing a charstring template with an unbound "
2124 return (*this)[(int)index_value
];
2127 boolean
CHARSTRING_template::match(const CHARSTRING
& other_value
) const
2129 if (!other_value
.is_bound()) return FALSE
;
2130 int value_length
= other_value
.lengthof();
2131 if (!match_length(value_length
)) return FALSE
;
2132 switch (template_selection
) {
2133 case SPECIFIC_VALUE
:
2134 return single_value
== other_value
;
2135 case STRING_PATTERN
: {
2136 if (!pattern_value
.regexp_init
) {
2137 char *posix_str
=TTCN_pattern_to_regexp(single_value
);
2138 if(posix_str
==NULL
) {
2139 TTCN_error("Cannot convert pattern \"%s\" to POSIX-equivalent.",
2140 (const char*)single_value
);
2143 //TTCN_Logger::begin_event(TTCN_DEBUG);
2144 TTCN_Logger::log_event_str("POSIX ERE equivalent of pattern ");
2146 TTCN_Logger::log_event(" is: \"%s\"", posix_str);
2147 //TTCN_Logger::end_event();
2149 int ret_val
=regcomp(&pattern_value
.posix_regexp
, posix_str
,
2150 REG_EXTENDED
|REG_NOSUB
);
2154 char msg
[ERRMSG_BUFSIZE
];
2155 regerror(ret_val
, &pattern_value
.posix_regexp
, msg
, ERRMSG_BUFSIZE
);
2156 regfree(&pattern_value
.posix_regexp
);
2157 TTCN_error("Pattern matching error: %s", msg
);
2159 pattern_value
.regexp_init
=TRUE
;
2161 int ret_val
=regexec(&pattern_value
.posix_regexp
, other_value
, 0, NULL
, 0);
2169 char msg
[ERRMSG_BUFSIZE
];
2170 regerror(ret_val
, &pattern_value
.posix_regexp
, msg
, ERRMSG_BUFSIZE
);
2171 TTCN_error("Pattern matching error: %s", msg
);
2180 case COMPLEMENTED_LIST
:
2181 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2182 if (value_list
.list_value
[i
].match(other_value
))
2183 return template_selection
== VALUE_LIST
;
2184 return template_selection
== COMPLEMENTED_LIST
;
2186 if (!value_range
.min_is_set
) TTCN_error("The lower bound is not set when "
2187 "matching with a charstring value range template.");
2188 if (!value_range
.max_is_set
) TTCN_error("The upper bound is not set when "
2189 "matching with a charstring value range template.");
2190 if (value_range
.min_value
> value_range
.max_value
)
2191 TTCN_error("The lower bound (\"%c\") is greater than the upper bound "
2192 "(\"%c\") when matching with a charstring value range template.",
2193 value_range
.min_value
, value_range
.max_value
);
2194 const char *chars_ptr
= other_value
;
2195 for (int i
= 0; i
< value_length
; i
++) {
2196 if (chars_ptr
[i
] < value_range
.min_value
||
2197 chars_ptr
[i
] > value_range
.max_value
) return FALSE
;
2202 TTCN_error("Matching with an uninitialized/unsupported charstring "
2208 const CHARSTRING
& CHARSTRING_template::valueof() const
2210 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
2211 TTCN_error("Performing valueof or send operation on a non-specific "
2212 "charstring template.");
2213 return single_value
;
2216 int CHARSTRING_template::lengthof() const
2219 boolean has_any_or_none
;
2221 TTCN_error("Performing lengthof() operation on a charstring template "
2222 "which has an ifpresent attribute.");
2223 switch (template_selection
)
2225 case SPECIFIC_VALUE
:
2226 min_length
= single_value
.lengthof();
2227 has_any_or_none
= FALSE
;
2230 TTCN_error("Performing lengthof() operation on a charstring template "
2231 "containing omit value.");
2236 has_any_or_none
= TRUE
; // max. length is infinity
2240 // error if any element does not have length or the lengths differ
2241 if (value_list
.n_values
<1)
2242 TTCN_error("Internal error: "
2243 "Performing lengthof() operation on a charstring template "
2244 "containing an empty list.");
2245 int item_length
= value_list
.list_value
[0].lengthof();
2246 for (unsigned int i
= 1; i
< value_list
.n_values
; i
++) {
2247 if (value_list
.list_value
[i
].lengthof()!=item_length
)
2248 TTCN_error("Performing lengthof() operation on a charstring template "
2249 "containing a value list with different lengths.");
2251 min_length
= item_length
;
2252 has_any_or_none
= FALSE
;
2255 case COMPLEMENTED_LIST
:
2256 TTCN_error("Performing lengthof() operation on a charstring template "
2257 "containing complemented list.");
2258 case STRING_PATTERN
:
2259 TTCN_error("Performing lengthof() operation on a charstring template "
2260 "containing a pattern is not allowed.");
2262 TTCN_error("Performing lengthof() operation on an "
2263 "uninitialized/unsupported charstring template.");
2265 return check_section_is_single(min_length
, has_any_or_none
,
2266 "length", "a", "charstring template");
2269 void CHARSTRING_template::set_type(template_sel template_type
,
2270 unsigned int list_length
)
2273 switch (template_type
) {
2275 case COMPLEMENTED_LIST
:
2276 set_selection(template_type
);
2277 value_list
.n_values
= list_length
;
2278 value_list
.list_value
= new CHARSTRING_template
[list_length
];
2281 set_selection(VALUE_RANGE
);
2282 value_range
.min_is_set
= FALSE
;
2283 value_range
.max_is_set
= FALSE
;
2286 TTCN_error("Setting an invalid type for a charstring template.");
2290 CHARSTRING_template
& CHARSTRING_template::list_item(unsigned int list_index
)
2292 if (template_selection
!= VALUE_LIST
&&
2293 template_selection
!= COMPLEMENTED_LIST
)
2294 TTCN_error("Internal error: Accessing a list element of a non-list "
2295 "charstring template.");
2296 if (list_index
>= value_list
.n_values
)
2297 TTCN_error("Internal error: Index overflow in a charstring value list "
2299 return value_list
.list_value
[list_index
];
2302 void CHARSTRING_template::set_min(const CHARSTRING
& min_value
)
2304 if (template_selection
!= VALUE_RANGE
)
2305 TTCN_error("Setting the lower bound for a non-range charstring template.");
2306 min_value
.must_bound("Setting an unbound value as lower bound in a "
2307 "charstring value range template.");
2308 int length
= min_value
.lengthof();
2309 if (length
!= 1) TTCN_error("The length of the lower bound in a "
2310 "charstring value range template must be 1 instead of %d.", length
);
2311 value_range
.min_is_set
= TRUE
;
2312 value_range
.min_value
= *(const char*)min_value
;
2313 if (value_range
.max_is_set
&& value_range
.min_value
> value_range
.max_value
)
2314 TTCN_error("The lower bound (\"%c\") in a charstring value range template "
2315 "is greater than the upper bound (\"%c\").", value_range
.min_value
,
2316 value_range
.max_value
);
2319 void CHARSTRING_template::set_max(const CHARSTRING
& max_value
)
2321 if (template_selection
!= VALUE_RANGE
)
2322 TTCN_error("Setting the upper bound for a non-range charstring template.");
2323 max_value
.must_bound("Setting an unbound value as upper bound in a "
2324 "charstring value range template.");
2325 int length
= max_value
.lengthof();
2326 if (length
!= 1) TTCN_error("The length of the upper bound in a "
2327 "charstring value range template must be 1 instead of %d.", length
);
2328 value_range
.max_is_set
= TRUE
;
2329 value_range
.max_value
= *(const char*)max_value
;
2330 if (value_range
.min_is_set
&& value_range
.min_value
> value_range
.max_value
)
2331 TTCN_error("The upper bound (\"%c\") in a charstring value range template "
2332 "is smaller than the lower bound (\"%c\").", value_range
.max_value
,
2333 value_range
.min_value
);
2336 void CHARSTRING_template::log_pattern(int n_chars
, const char *chars_ptr
)
2338 TTCN_Logger::log_event_str("pattern \"");
2339 enum { INITIAL
, BACKSLASH
, BACKSLASH_Q
, QUADRUPLE
, HASHMARK
, REPETITIONS
}
2341 for (int i
= 0; i
< n_chars
; i
++) {
2342 unsigned char c
= chars_ptr
[i
];
2343 // print the character
2347 TTCN_Logger::log_event_str("\\\"");
2350 if (state
== BACKSLASH
|| state
== BACKSLASH_Q
)
2351 TTCN_Logger::log_char('{');
2352 else TTCN_Logger::log_event_str("\\{");
2355 if (state
== BACKSLASH
|| state
== QUADRUPLE
)
2356 TTCN_Logger::log_char('}');
2357 else TTCN_Logger::log_event_str("\\}");
2360 if (state
!= INITIAL
&& state
!= BACKSLASH
) break;
2363 TTCN_Logger::log_char(c
);
2369 if (state
== INITIAL
|| state
== BACKSLASH
)
2370 TTCN_Logger::log_event_str("\\t");
2373 if (state
== INITIAL
|| state
== BACKSLASH
)
2374 TTCN_Logger::log_event_str("\\r");
2379 if (state
!= INITIAL
&& state
!= BACKSLASH
) break;
2382 TTCN_Logger::log_event("\\q{0,0,0,%u}", c
);
2401 if (c
== 'q') state
= BACKSLASH_Q
;
2402 else state
= INITIAL
;
2424 state
= REPETITIONS
;
2450 if (!isdigit(c
)) state
= INITIAL
;
2456 TTCN_Logger::log_char('"');
2459 void CHARSTRING_template::log() const
2461 switch (template_selection
) {
2462 case STRING_PATTERN
:
2463 log_pattern(single_value
.lengthof(), (const char*)single_value
);
2465 case SPECIFIC_VALUE
:
2468 case COMPLEMENTED_LIST
:
2469 TTCN_Logger::log_event_str("complement ");
2472 TTCN_Logger::log_char('(');
2473 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++) {
2474 if (i
> 0) TTCN_Logger::log_event_str(", ");
2475 value_list
.list_value
[i
].log();
2477 TTCN_Logger::log_char(')');
2480 TTCN_Logger::log_char('(');
2481 if (value_range
.min_is_set
) {
2482 if (TTCN_Logger::is_printable(value_range
.min_value
)) {
2483 TTCN_Logger::log_char('"');
2484 TTCN_Logger::log_char_escaped(value_range
.min_value
);
2485 TTCN_Logger::log_char('"');
2486 } else TTCN_Logger::log_event("char(0, 0, 0, %u)",
2487 (unsigned char)value_range
.min_value
);
2488 } else TTCN_Logger::log_event_str("<unknown lower bound>");
2489 TTCN_Logger::log_event_str(" .. ");
2490 if (value_range
.max_is_set
) {
2491 if (TTCN_Logger::is_printable(value_range
.max_value
)) {
2492 TTCN_Logger::log_char('"');
2493 TTCN_Logger::log_char_escaped(value_range
.max_value
);
2494 TTCN_Logger::log_char('"');
2495 } else TTCN_Logger::log_event("char(0, 0, 0, %u)",
2496 (unsigned char)value_range
.max_value
);
2497 } else TTCN_Logger::log_event_str("<unknown upper bound>");
2498 TTCN_Logger::log_char(')');
2507 void CHARSTRING_template::log_match(const CHARSTRING
& match_value
) const
2509 if (TTCN_Logger::VERBOSITY_COMPACT
== TTCN_Logger::get_matching_verbosity()
2510 && TTCN_Logger::get_logmatch_buffer_len() != 0) {
2511 TTCN_Logger::print_logmatch_buffer();
2512 TTCN_Logger::log_event_str(" := ");
2515 TTCN_Logger::log_event_str(" with ");
2517 if (match(match_value
)) TTCN_Logger::log_event_str(" matched");
2518 else TTCN_Logger::log_event_str(" unmatched");
2521 void CHARSTRING_template::set_param(Module_Param
& param
) {
2522 param
.basic_check(Module_Param::BC_TEMPLATE
|Module_Param::BC_LIST
, "charstring template");
2523 switch (param
.get_type()) {
2524 case Module_Param::MP_Omit
:
2527 case Module_Param::MP_Any
:
2530 case Module_Param::MP_AnyOrNone
:
2531 *this = ANY_OR_OMIT
;
2533 case Module_Param::MP_List_Template
:
2534 case Module_Param::MP_ComplementList_Template
:
2535 set_type(param
.get_type()==Module_Param::MP_List_Template
? VALUE_LIST
: COMPLEMENTED_LIST
, param
.get_size());
2536 for (size_t i
=0; i
<param
.get_size(); i
++) {
2537 list_item(i
).set_param(*param
.get_elem(i
));
2540 case Module_Param::MP_Charstring
:
2541 *this = CHARSTRING(param
.get_string_size(), (char*)param
.get_string_data());
2543 case Module_Param::MP_StringRange
: {
2544 universal_char lower_uchar
= param
.get_lower_uchar();
2545 universal_char upper_uchar
= param
.get_upper_uchar();
2546 if (!lower_uchar
.is_char()) param
.error("Lower bound of char range cannot be a multiple-byte character");
2547 if (!upper_uchar
.is_char()) param
.error("Upper bound of char range cannot be a multiple-byte character");
2549 set_selection(VALUE_RANGE
);
2550 value_range
.min_is_set
= TRUE
;
2551 value_range
.max_is_set
= TRUE
;
2552 value_range
.min_value
= (char)(lower_uchar
.uc_cell
);
2553 value_range
.max_value
= (char)(upper_uchar
.uc_cell
);
2555 case Module_Param::MP_Pattern
:
2557 single_value
= CHARSTRING(param
.get_pattern());
2558 pattern_value
.regexp_init
= FALSE
;
2559 set_selection(STRING_PATTERN
);
2562 param
.type_error("charstring template");
2564 is_ifpresent
= param
.get_ifpresent();
2565 set_length_range(param
);
2568 void CHARSTRING_template::encode_text(Text_Buf
& text_buf
) const
2570 encode_text_restricted(text_buf
);
2571 switch (template_selection
) {
2576 case SPECIFIC_VALUE
:
2577 case STRING_PATTERN
:
2578 single_value
.encode_text(text_buf
);
2581 case COMPLEMENTED_LIST
:
2582 text_buf
.push_int(value_list
.n_values
);
2583 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2584 value_list
.list_value
[i
].encode_text(text_buf
);
2587 if (!value_range
.min_is_set
) TTCN_error("Text encoder: The lower bound is "
2588 "not set in a charstring value range template.");
2589 if (!value_range
.max_is_set
) TTCN_error("Text encoder: The upper bound is "
2590 "not set in a charstring value range template.");
2591 text_buf
.push_raw(1, &value_range
.min_value
);
2592 text_buf
.push_raw(1, &value_range
.max_value
);
2595 TTCN_error("Text encoder: Encoding an uninitialized/unsupported "
2596 "charstring template.");
2600 void CHARSTRING_template::decode_text(Text_Buf
& text_buf
)
2603 decode_text_restricted(text_buf
);
2604 switch (template_selection
) {
2609 case STRING_PATTERN
:
2610 pattern_value
.regexp_init
=FALSE
;
2612 case SPECIFIC_VALUE
:
2613 single_value
.decode_text(text_buf
);
2616 case COMPLEMENTED_LIST
:
2617 value_list
.n_values
= text_buf
.pull_int().get_val();
2618 value_list
.list_value
= new CHARSTRING_template
[value_list
.n_values
];
2619 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2620 value_list
.list_value
[i
].decode_text(text_buf
);
2623 text_buf
.pull_raw(1, &value_range
.min_value
);
2624 text_buf
.pull_raw(1, &value_range
.max_value
);
2625 if (value_range
.min_value
> value_range
.max_value
)
2626 TTCN_error("Text decoder: The received lower bound is greater than the "
2627 "upper bound in a charstring value range template.");
2628 value_range
.min_is_set
= TRUE
;
2629 value_range
.max_is_set
= TRUE
;
2632 TTCN_error("Text decoder: An unknown/unsupported selection was "
2633 "received for a charstring template.");
2637 boolean
CHARSTRING_template::is_present() const
2639 if (template_selection
==UNINITIALIZED_TEMPLATE
) return FALSE
;
2640 return !match_omit();
2643 boolean
CHARSTRING_template::match_omit() const
2645 if (is_ifpresent
) return TRUE
;
2646 switch (template_selection
) {
2651 case COMPLEMENTED_LIST
:
2652 for (unsigned int i
=0; i
<value_list
.n_values
; i
++)
2653 if (value_list
.list_value
[i
].match_omit())
2654 return template_selection
==VALUE_LIST
;
2655 return template_selection
==COMPLEMENTED_LIST
;
2662 #ifndef TITAN_RUNTIME_2
2663 void CHARSTRING_template::check_restriction(template_res t_res
, const char* t_name
) const
2665 if (template_selection
==UNINITIALIZED_TEMPLATE
) return;
2666 switch ((t_name
&&(t_res
==TR_VALUE
))?TR_OMIT
:t_res
) {
2668 if (!is_ifpresent
&& template_selection
==SPECIFIC_VALUE
) return;
2671 if (!is_ifpresent
&& (template_selection
==OMIT_VALUE
||
2672 template_selection
==SPECIFIC_VALUE
)) return;
2675 if (!match_omit()) return;
2680 TTCN_error("Restriction `%s' on template of type %s violated.",
2681 get_res_name(t_res
), t_name
? t_name
: "charstring");
2685 const CHARSTRING
& CHARSTRING_template::get_single_value() const {
2686 switch (template_selection
) {
2687 case STRING_PATTERN
:
2688 case SPECIFIC_VALUE
:
2691 TTCN_error("This template does not have single value.");
2693 return single_value
;