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
19 * Szabo, Janos Zoltan – initial implementation
22 * Zalanyi, Balazs Andor
25 ******************************************************************************/
26 #include "Charstring.hh"
27 #include "../common/memory.h"
28 #include "../common/pattern.hh"
30 #include "Octetstring.hh"
31 #include "String_struct.hh"
32 #include "Parameters.h"
33 #include "Param_Types.hh"
44 #include "../common/dbgnew.hh"
50 #define ERRMSG_BUFSIZE 500
52 /** The amount of memory needed for a string containing n characters.
53 * -sizeof(int) because that much is already in charstring_struct.
54 * +1 for the terminating null character. */
55 #define MEMORY_SIZE(n) (sizeof(charstring_struct) - sizeof(int) + 1 + (n))
57 /** Allocate the memory needed to hold n_chars characters.
59 * @param \p n_chars the number of characters to hold
60 * @pre \p n_chars must be >= 0
62 void CHARSTRING::init_struct(int n_chars
)
66 TTCN_error("Initializing a charstring with a negative length.");
67 } else if (n_chars
== 0) {
68 /** This will represent the empty strings so they won't need allocated
69 * memory, this delays the memory allocation until it is really needed.
71 static charstring_struct empty_string
= { 1, 0, "" };
72 val_ptr
= &empty_string
;
73 empty_string
.ref_count
++;
75 val_ptr
= (charstring_struct
*)Malloc(MEMORY_SIZE(n_chars
));
76 val_ptr
->ref_count
= 1;
77 val_ptr
->n_chars
= n_chars
;
78 val_ptr
->chars_ptr
[n_chars
] = '\0';
82 /** Implement the copy-on-write.
84 * Called from the various CHARSTRING_ELEMENT::operator=(), just before
85 * the string is about to be modified. Stops the sharing of the CHARSTRING
86 * and creates a new copy for modification.
88 void CHARSTRING::copy_value()
90 if (val_ptr
== NULL
|| val_ptr
->n_chars
<= 0)
91 TTCN_error("Internal error: Invalid internal data structure when copying "
92 "the memory area of a charstring value.");
93 if (val_ptr
->ref_count
> 1) {
94 charstring_struct
*old_ptr
= val_ptr
;
96 init_struct(old_ptr
->n_chars
);
97 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
+ 1);
101 /** Create an uninitialized CHARSTRING object.
103 * Called from CHARSTRING::operator+() to create the return value with
104 * enough storage to hold the concatenation of the arguments.
106 * @param n_chars the number of characters to hold
109 CHARSTRING::CHARSTRING(int n_chars
)
111 init_struct(n_chars
);
114 CHARSTRING::CHARSTRING()
119 CHARSTRING::CHARSTRING(char other_value
)
122 val_ptr
->chars_ptr
[0] = other_value
;
125 CHARSTRING::CHARSTRING(const char *chars_ptr
)
128 if (chars_ptr
!= NULL
) n_chars
= strlen(chars_ptr
);
130 init_struct(n_chars
);
131 memcpy(val_ptr
->chars_ptr
, chars_ptr
, n_chars
);
134 CHARSTRING::CHARSTRING(int n_chars
, const char *chars_ptr
)
136 init_struct(n_chars
);
137 memcpy(val_ptr
->chars_ptr
, chars_ptr
, n_chars
);
140 CHARSTRING::CHARSTRING(const CHARSTRING
& other_value
)
141 : Base_Type(other_value
), val_ptr(other_value
.val_ptr
)
143 other_value
.must_bound("Copying an unbound charstring value.");
144 // ref_count can only be incremented after we check val_ptr
145 val_ptr
->ref_count
++;
148 CHARSTRING::CHARSTRING(const CHARSTRING_ELEMENT
& other_value
)
150 other_value
.must_bound("Initialization of a charstring with an unbound "
151 "charstring element.");
153 val_ptr
->chars_ptr
[0] = other_value
.get_char();
156 CHARSTRING::~CHARSTRING()
161 void CHARSTRING::clean_up()
163 if (val_ptr
!= NULL
) {
164 if (val_ptr
->ref_count
> 1) val_ptr
->ref_count
--;
165 else if (val_ptr
->ref_count
== 1) Free(val_ptr
);
166 else TTCN_error("Internal error: Invalid reference counter in a charstring "
172 CHARSTRING
& CHARSTRING::operator=(const char* other_value
)
174 if (val_ptr
== NULL
|| val_ptr
->chars_ptr
!= other_value
) {
177 if (other_value
!= NULL
) n_chars
= strlen(other_value
);
179 init_struct(n_chars
);
180 memcpy(val_ptr
->chars_ptr
, other_value
, n_chars
);
185 CHARSTRING
& CHARSTRING::operator=(const CHARSTRING
& other_value
)
187 other_value
.must_bound("Assignment of an unbound charstring value.");
188 if (&other_value
!= this) {
190 val_ptr
= other_value
.val_ptr
;
191 val_ptr
->ref_count
++;
196 CHARSTRING
& CHARSTRING::operator=(const CHARSTRING_ELEMENT
& other_value
)
198 other_value
.must_bound("Assignment of an unbound charstring element to "
200 char char_value
= other_value
.get_char();
203 val_ptr
->chars_ptr
[0] = char_value
;
207 CHARSTRING
& CHARSTRING::operator=(const UNIVERSAL_CHARSTRING
& other_value
)
209 other_value
.must_bound("Assignment of an unbound universal charstring to "
212 int n_chars
= other_value
.val_ptr
->n_uchars
;
213 init_struct(n_chars
);
214 for (int i
= 0; i
< n_chars
; ++i
) {
215 const universal_char
& uc
= other_value
.val_ptr
->uchars_ptr
[i
];
216 if (uc
.uc_group
!= 0 || uc
.uc_plane
!= 0 || uc
.uc_row
!= 0) {
217 TTCN_error("Multiple-byte characters cannot be assigned to a charstring, "
218 "invalid character char(%u, %u, %u, %u) at index %d.",
219 uc
.uc_group
, uc
.uc_plane
, uc
.uc_row
, uc
.uc_cell
, i
);
221 val_ptr
->chars_ptr
[i
] = other_value
.val_ptr
->uchars_ptr
[i
].uc_cell
;
226 boolean
CHARSTRING::operator==(const char* other_value
) const
228 must_bound("Unbound operand of charstring comparison.");
229 if (other_value
== NULL
) other_value
= "";
230 return !strcmp(val_ptr
->chars_ptr
, other_value
);
233 boolean
CHARSTRING::operator==(const CHARSTRING
& other_value
) const
235 must_bound("Unbound operand of charstring comparison.");
236 other_value
.must_bound("Unbound operand of charstring comparison.");
237 if (val_ptr
->n_chars
!= other_value
.val_ptr
->n_chars
) return FALSE
;
238 else return !memcmp(val_ptr
->chars_ptr
, other_value
.val_ptr
->chars_ptr
,
242 boolean
CHARSTRING::operator==(const CHARSTRING_ELEMENT
& other_value
) const
244 other_value
.must_bound("Unbound operand of charstring element "
246 must_bound("Unbound operand of charstring comparison.");
247 if (val_ptr
->n_chars
!= 1) return FALSE
;
248 else return val_ptr
->chars_ptr
[0] == other_value
.get_char();
251 boolean
CHARSTRING::operator==(const UNIVERSAL_CHARSTRING
& other_value
) const
253 must_bound("The left operand of comparison is an unbound charstring value.");
254 other_value
.must_bound("The right operand of comparison is an unbound "
255 "universal charstring value.");
256 if (other_value
.charstring
)
257 return *this == other_value
.cstr
;
258 if (val_ptr
->n_chars
!= other_value
.val_ptr
->n_uchars
) return FALSE
;
259 for (int i
= 0; i
< val_ptr
->n_chars
; i
++) {
260 if (other_value
.val_ptr
->uchars_ptr
[i
].uc_group
!= 0 ||
261 other_value
.val_ptr
->uchars_ptr
[i
].uc_plane
!= 0 ||
262 other_value
.val_ptr
->uchars_ptr
[i
].uc_row
!= 0 ||
263 other_value
.val_ptr
->uchars_ptr
[i
].uc_cell
!= (cbyte
)val_ptr
->chars_ptr
[i
])
269 boolean
CHARSTRING::operator==(const UNIVERSAL_CHARSTRING_ELEMENT
& other_value
)
272 must_bound("The left operand of comparison is an unbound charstring value.");
273 other_value
.must_bound("The right operand of comparison is an unbound "
274 "universal charstring element.");
275 if (val_ptr
->n_chars
!= 1) return FALSE
;
276 const universal_char
& uchar
= other_value
.get_uchar();
277 return uchar
.uc_group
== 0 && uchar
.uc_plane
== 0 && uchar
.uc_row
== 0 &&
278 uchar
.uc_cell
== (cbyte
)val_ptr
->chars_ptr
[0];
281 CHARSTRING
CHARSTRING::operator+(const char* other_value
) const
283 must_bound("Unbound operand of charstring concatenation.");
285 if (other_value
== NULL
) other_len
= 0;
286 else other_len
= strlen(other_value
);
287 if (other_len
== 0) return *this;
288 CHARSTRING
ret_val(val_ptr
->n_chars
+ other_len
);
289 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, val_ptr
->n_chars
);
290 memcpy(ret_val
.val_ptr
->chars_ptr
+ val_ptr
->n_chars
, other_value
, other_len
);
294 CHARSTRING
CHARSTRING::operator+(const CHARSTRING
& other_value
) const
296 must_bound("Unbound operand of charstring concatenation.");
297 other_value
.must_bound("Unbound operand of charstring concatenation.");
298 int first_n_chars
= val_ptr
->n_chars
;
299 if (first_n_chars
== 0) return other_value
;
300 int second_n_chars
= other_value
.val_ptr
->n_chars
;
301 if (second_n_chars
== 0) return *this;
302 CHARSTRING
ret_val(first_n_chars
+ second_n_chars
);
303 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, first_n_chars
);
304 memcpy(ret_val
.val_ptr
->chars_ptr
+ first_n_chars
,
305 other_value
.val_ptr
->chars_ptr
, second_n_chars
);
309 CHARSTRING
CHARSTRING::operator+(const CHARSTRING_ELEMENT
& other_value
) const
311 must_bound("Unbound operand of charstring concatenation.");
312 other_value
.must_bound("Unbound operand of charstring element "
314 CHARSTRING
ret_val(val_ptr
->n_chars
+ 1);
315 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, val_ptr
->n_chars
);
316 ret_val
.val_ptr
->chars_ptr
[val_ptr
->n_chars
] = other_value
.get_char();
320 UNIVERSAL_CHARSTRING
CHARSTRING::operator+
321 (const UNIVERSAL_CHARSTRING
& other_value
) const
323 must_bound("The left operand of concatenation is an unbound charstring "
325 other_value
.must_bound("The right operand of concatenation is an unbound "
326 "universal charstring value.");
327 if (val_ptr
->n_chars
== 0) return other_value
;
328 if (other_value
.charstring
) {
329 UNIVERSAL_CHARSTRING
ret_val(val_ptr
->n_chars
+ other_value
.cstr
.val_ptr
->n_chars
, true);
330 memcpy(ret_val
.cstr
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, val_ptr
->n_chars
);
331 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
);
334 UNIVERSAL_CHARSTRING
ret_val(val_ptr
->n_chars
+
335 other_value
.val_ptr
->n_uchars
);
336 for (int i
= 0; i
< val_ptr
->n_chars
; i
++) {
337 ret_val
.val_ptr
->uchars_ptr
[i
].uc_group
= 0;
338 ret_val
.val_ptr
->uchars_ptr
[i
].uc_plane
= 0;
339 ret_val
.val_ptr
->uchars_ptr
[i
].uc_row
= 0;
340 ret_val
.val_ptr
->uchars_ptr
[i
].uc_cell
= val_ptr
->chars_ptr
[i
];
342 memcpy(ret_val
.val_ptr
->uchars_ptr
+ val_ptr
->n_chars
,
343 other_value
.val_ptr
->uchars_ptr
,
344 other_value
.val_ptr
->n_uchars
* sizeof(universal_char
));
349 UNIVERSAL_CHARSTRING
CHARSTRING::operator+
350 (const UNIVERSAL_CHARSTRING_ELEMENT
& other_value
) const
352 must_bound("The left operand of concatenation is an unbound charstring "
354 other_value
.must_bound("The right operand of concatenation is an unbound "
355 "universal charstring element.");
356 if (other_value
.str_val
.charstring
) {
357 UNIVERSAL_CHARSTRING
ret_val(val_ptr
->n_chars
+ 1, true);
358 memcpy(ret_val
.cstr
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, val_ptr
->n_chars
);
359 ret_val
.cstr
.val_ptr
->chars_ptr
[val_ptr
->n_chars
] = other_value
.str_val
.cstr
.val_ptr
->chars_ptr
[other_value
.uchar_pos
];
362 UNIVERSAL_CHARSTRING
ret_val(val_ptr
->n_chars
+ 1);
363 for (int i
= 0; i
< val_ptr
->n_chars
; i
++) {
364 ret_val
.val_ptr
->uchars_ptr
[i
].uc_group
= 0;
365 ret_val
.val_ptr
->uchars_ptr
[i
].uc_plane
= 0;
366 ret_val
.val_ptr
->uchars_ptr
[i
].uc_row
= 0;
367 ret_val
.val_ptr
->uchars_ptr
[i
].uc_cell
= val_ptr
->chars_ptr
[i
];
369 ret_val
.val_ptr
->uchars_ptr
[val_ptr
->n_chars
] = other_value
.get_uchar();
374 CHARSTRING
& CHARSTRING::operator+=(char other_value
)
376 must_bound("Appending a character to an unbound charstring value.");
377 if (val_ptr
->ref_count
> 1) {
378 charstring_struct
*old_ptr
= val_ptr
;
379 old_ptr
->ref_count
--;
380 init_struct(old_ptr
->n_chars
+ 1);
381 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
);
382 val_ptr
->chars_ptr
[old_ptr
->n_chars
] = other_value
;
384 val_ptr
= (charstring_struct
*)
385 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ 1));
386 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = other_value
;
388 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
393 CHARSTRING
& CHARSTRING::operator+=(const char *other_value
)
395 must_bound("Appending a string literal to an unbound charstring value.");
396 if (other_value
!= NULL
) {
397 int other_n_chars
= strlen(other_value
);
398 if (other_n_chars
> 0) {
399 if (val_ptr
->ref_count
> 1) {
400 charstring_struct
*old_ptr
= val_ptr
;
401 old_ptr
->ref_count
--;
402 init_struct(old_ptr
->n_chars
+ other_n_chars
);
403 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
);
404 memcpy(val_ptr
->chars_ptr
+ old_ptr
->n_chars
, other_value
,
407 if (other_value
>= val_ptr
->chars_ptr
&&
408 other_value
<= val_ptr
->chars_ptr
+ val_ptr
->n_chars
) {
409 int offset
= other_value
- val_ptr
->chars_ptr
;
410 val_ptr
= (charstring_struct
*)
411 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ other_n_chars
));
412 memcpy(val_ptr
->chars_ptr
+ val_ptr
->n_chars
,
413 val_ptr
->chars_ptr
+ offset
, other_n_chars
);
415 val_ptr
= (charstring_struct
*)
416 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ other_n_chars
));
417 memcpy(val_ptr
->chars_ptr
+ val_ptr
->n_chars
, other_value
,
420 val_ptr
->n_chars
+= other_n_chars
;
421 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
428 CHARSTRING
& CHARSTRING::operator+=(const CHARSTRING
& other_value
)
430 must_bound("Appending a charstring value to an unbound charstring value.");
431 other_value
.must_bound("Appending an unbound charstring value to another "
432 "charstring value.");
433 int other_n_chars
= other_value
.val_ptr
->n_chars
;
434 if (other_n_chars
> 0) {
435 if (val_ptr
->n_chars
== 0) {
437 val_ptr
= other_value
.val_ptr
;
438 val_ptr
->ref_count
++;
439 } else if (val_ptr
->ref_count
> 1) {
440 charstring_struct
*old_ptr
= val_ptr
;
441 old_ptr
->ref_count
--;
442 init_struct(old_ptr
->n_chars
+ other_n_chars
);
443 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
);
444 memcpy(val_ptr
->chars_ptr
+ old_ptr
->n_chars
,
445 other_value
.val_ptr
->chars_ptr
, other_n_chars
);
447 val_ptr
= (charstring_struct
*)
448 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ other_n_chars
));
449 memcpy(val_ptr
->chars_ptr
+ val_ptr
->n_chars
,
450 other_value
.val_ptr
->chars_ptr
, other_n_chars
);
451 val_ptr
->n_chars
+= other_n_chars
;
452 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
458 CHARSTRING
& CHARSTRING::operator+=(const CHARSTRING_ELEMENT
& other_value
)
460 must_bound("Appending a charstring element to an unbound charstring value.");
461 other_value
.must_bound("Appending an unbound charstring element to a "
462 "charstring value.");
463 if (val_ptr
->ref_count
> 1) {
464 charstring_struct
*old_ptr
= val_ptr
;
465 old_ptr
->ref_count
--;
466 init_struct(old_ptr
->n_chars
+ 1);
467 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
);
468 val_ptr
->chars_ptr
[old_ptr
->n_chars
] = other_value
.get_char();
470 val_ptr
= (charstring_struct
*)
471 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ 1));
472 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = other_value
.get_char();
474 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
479 CHARSTRING
CHARSTRING::operator<<=(int rotate_count
) const
481 must_bound("Unbound charstring operand of rotate left operator.");
482 if (val_ptr
->n_chars
== 0) return *this;
483 if (rotate_count
>= 0) {
484 rotate_count
%= val_ptr
->n_chars
;
485 if (rotate_count
== 0) return *this;
486 CHARSTRING
ret_val(val_ptr
->n_chars
);
487 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
+ rotate_count
,
488 val_ptr
->n_chars
- rotate_count
);
489 memcpy(ret_val
.val_ptr
->chars_ptr
+ val_ptr
->n_chars
- rotate_count
,
490 val_ptr
->chars_ptr
, rotate_count
);
492 } else return *this >>= (-rotate_count
);
495 CHARSTRING
CHARSTRING::operator<<=(const INTEGER
& rotate_count
) const
497 rotate_count
.must_bound("Unbound integer operand of rotate left "
499 return *this <<= (int)rotate_count
;
502 CHARSTRING
CHARSTRING::operator>>=(int rotate_count
) const
504 must_bound("Unbound charstring operand of rotate right operator.");
505 if (val_ptr
->n_chars
== 0) return *this;
506 if (rotate_count
>= 0) {
507 rotate_count
%= val_ptr
->n_chars
;
508 if (rotate_count
== 0) return *this;
509 CHARSTRING
ret_val(val_ptr
->n_chars
);
510 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
+ val_ptr
->n_chars
-
511 rotate_count
, rotate_count
);
512 memcpy(ret_val
.val_ptr
->chars_ptr
+ rotate_count
, val_ptr
->chars_ptr
,
513 val_ptr
->n_chars
- rotate_count
);
515 } else return *this <<= (-rotate_count
);
518 CHARSTRING
CHARSTRING::operator>>=(const INTEGER
& rotate_count
) const
520 rotate_count
.must_bound("Unbound integer operand of rotate right "
522 return *this >>= (int)rotate_count
;
525 CHARSTRING_ELEMENT
CHARSTRING::operator[](int index_value
)
527 if (val_ptr
== NULL
&& index_value
== 0) {
529 return CHARSTRING_ELEMENT(FALSE
, *this, 0);
531 must_bound("Accessing an element of an unbound charstring value.");
532 if (index_value
< 0) TTCN_error("Accessing a charstring element using a "
533 "negative index (%d).", index_value
);
534 int n_chars
= val_ptr
->n_chars
;
535 if (index_value
> n_chars
) TTCN_error("Index overflow when accessing a "
536 "charstring element: The index is %d, but the string has only %d "
537 "characters.", index_value
, n_chars
);
538 if (index_value
== n_chars
) {
539 if (val_ptr
->ref_count
== 1) {
540 val_ptr
= (charstring_struct
*)
541 Realloc(val_ptr
, MEMORY_SIZE(n_chars
+ 1));
543 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
545 charstring_struct
*old_ptr
= val_ptr
;
546 old_ptr
->ref_count
--;
547 init_struct(n_chars
+ 1);
548 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, n_chars
);
550 return CHARSTRING_ELEMENT(FALSE
, *this, index_value
);
551 } else return CHARSTRING_ELEMENT(TRUE
, *this, index_value
);
555 CHARSTRING_ELEMENT
CHARSTRING::operator[](const INTEGER
& index_value
)
557 index_value
.must_bound("Indexing a charstring value with an unbound integer "
559 return (*this)[(int)index_value
];
562 const CHARSTRING_ELEMENT
CHARSTRING::operator[](int index_value
) const
564 must_bound("Accessing an element of an unbound charstring value.");
565 if (index_value
< 0) TTCN_error("Accessing a charstring element using a "
566 "negative index (%d).", index_value
);
567 if (index_value
>= val_ptr
->n_chars
) TTCN_error("Index overflow when "
568 "accessing a charstring element: The index is %d, but the string has only "
569 "%d characters.", index_value
, val_ptr
->n_chars
);
570 return CHARSTRING_ELEMENT(TRUE
, const_cast<CHARSTRING
&>(*this), index_value
);
573 const CHARSTRING_ELEMENT
CHARSTRING::operator[](const INTEGER
& index_value
) const
575 index_value
.must_bound("Indexing a charstring value with an unbound integer "
577 return (*this)[(int)index_value
];
580 CHARSTRING::operator const char*() const
582 must_bound("Casting an unbound charstring value to const char*.");
583 return val_ptr
->chars_ptr
;
586 int CHARSTRING::lengthof() const
588 must_bound("Performing lengthof operation on an unbound charstring value.");
589 return val_ptr
->n_chars
;
592 void CHARSTRING::log() const
594 if (val_ptr
!= NULL
) {
595 expstring_t buffer
= 0;
596 enum { INIT
, PCHAR
, NPCHAR
} state
= INIT
;
597 for (int i
= 0; i
< val_ptr
->n_chars
; i
++) {
598 char c
= val_ptr
->chars_ptr
[i
];
599 if (TTCN_Logger::is_printable(c
)) {
600 // the actual character is printable
602 case NPCHAR
: // concatenation sign if previous part was not printable
603 buffer
= mputstr(buffer
, " & ");
605 case INIT
: // opening "
606 buffer
= mputc(buffer
, '"');
608 case PCHAR
: // the character itself
609 TTCN_Logger::log_char_escaped(c
, buffer
);
614 // the actual character is not printable
616 case PCHAR
: // closing " if previous part was printable
617 buffer
= mputc(buffer
, '"');
619 case NPCHAR
: // concatenation sign
620 buffer
= mputstr(buffer
, " & ");
622 case INIT
: // the character itself
623 buffer
= mputprintf(buffer
, "char(0, 0, 0, %u)", (unsigned char)c
);
631 case INIT
: // the string was empty
632 buffer
= mputstr(buffer
, "\"\"");
634 case PCHAR
: // last character was printable -> closing "
635 buffer
= mputc(buffer
, '"');
640 TTCN_Logger::log_event_str(buffer
);
643 TTCN_Logger::log_event_unbound();
647 boolean
CHARSTRING::set_param_internal(Module_Param
& param
, boolean allow_pattern
) {
648 boolean is_pattern
= FALSE
;
649 param
.basic_check(Module_Param::BC_VALUE
|Module_Param::BC_LIST
, "charstring value");
650 Module_Param_Ptr mp
= ¶m
;
651 if (param
.get_type() == Module_Param::MP_Reference
) {
652 mp
= param
.get_referenced_param();
654 switch (mp
->get_type()) {
655 case Module_Param::MP_Universal_Charstring
:
656 case Module_Param::MP_Charstring
:
657 switch (param
.get_operation_type()) {
658 case Module_Param::OT_ASSIGN
:
661 case Module_Param::OT_CONCAT
: {
662 // The universal charstring will decode the string value if it is UTF-8 encoded
663 UNIVERSAL_CHARSTRING ucs
;
665 if (ucs
.charstring
) {
666 // No special characters were found
668 *this = *this + ucs
.cstr
;
673 // Special characters found -> check if the UTF-8 decoding resulted in any multi-byte characters
674 for (int i
= 0; i
< ucs
.val_ptr
->n_uchars
; ++i
) {
675 if (0 != ucs
.val_ptr
->uchars_ptr
[i
].uc_group
||
676 0 != ucs
.val_ptr
->uchars_ptr
[i
].uc_plane
||
677 0 != ucs
.val_ptr
->uchars_ptr
[i
].uc_row
) {
678 param
.error("Type mismatch: a charstring value without multi-octet characters was expected.");
681 CHARSTRING
new_cs(ucs
.val_ptr
->n_uchars
);
682 for (int i
= 0; i
< ucs
.val_ptr
->n_uchars
; ++i
) {
683 new_cs
.val_ptr
->chars_ptr
[i
] = ucs
.val_ptr
->uchars_ptr
[i
].uc_cell
;
686 *this = *this + new_cs
;
693 TTCN_error("Internal error: CHARSTRING::set_param()");
696 case Module_Param::MP_Expression
:
697 if (mp
->get_expr_type() == Module_Param::EXPR_CONCATENATE
) {
698 // only allow string patterns for the first operand
699 CHARSTRING operand1
, operand2
;
700 is_pattern
= operand1
.set_param_internal(*mp
->get_operand1(), allow_pattern
);
701 operand2
.set_param(*mp
->get_operand2());
702 if (param
.get_operation_type() == Module_Param::OT_CONCAT
) {
703 *this = *this + operand1
+ operand2
;
706 *this = operand1
+ operand2
;
710 param
.expr_type_error("a charstring");
713 case Module_Param::MP_Pattern
:
715 *this = CHARSTRING(mp
->get_pattern());
721 param
.type_error("charstring value");
727 void CHARSTRING::set_param(Module_Param
& param
) {
728 set_param_internal(param
, FALSE
);
731 Module_Param
* CHARSTRING::get_param(Module_Param_Name
& /* param_name */) const
734 return new Module_Param_Unbound();
736 return new Module_Param_Charstring(val_ptr
->n_chars
, mcopystr(val_ptr
->chars_ptr
));
739 void CHARSTRING::encode_text(Text_Buf
& text_buf
) const
741 must_bound("Text encoder: Encoding an unbound charstring value.");
742 int n_chars
= val_ptr
->n_chars
;
743 text_buf
.push_int(n_chars
);
744 if (n_chars
> 0) text_buf
.push_raw(n_chars
, val_ptr
->chars_ptr
);
747 void CHARSTRING::decode_text(Text_Buf
& text_buf
)
749 int n_chars
= text_buf
.pull_int().get_val();
751 TTCN_error("Text decoder: invalid length of a charstring.");
753 init_struct(n_chars
);
754 if (n_chars
> 0) text_buf
.pull_raw(n_chars
, val_ptr
->chars_ptr
);
757 void CHARSTRING::encode(const TTCN_Typedescriptor_t
& p_td
,
759 TTCN_EncDec::coding_t p_coding
, ...) const
762 va_start(pvar
, p_coding
);
764 case TTCN_EncDec::CT_BER
: {
765 TTCN_EncDec_ErrorContext
ec("While BER-encoding type '%s': ", p_td
.name
);
766 unsigned BER_coding
=va_arg(pvar
, unsigned);
767 BER_encode_chk_coding(BER_coding
);
768 ASN_BER_TLV_t
*tlv
=BER_encode_TLV(p_td
, BER_coding
);
769 tlv
->put_in_buffer(p_buf
);
770 ASN_BER_TLV_t::destruct(tlv
);
772 case TTCN_EncDec::CT_RAW
: {
773 TTCN_EncDec_ErrorContext
ec("While RAW-encoding type '%s': ", p_td
.name
);
775 TTCN_EncDec_ErrorContext::error_internal
776 ("No RAW descriptor available for type '%s'.", p_td
.name
);
780 RAW_enc_tree
root(TRUE
,NULL
,&rp
,1,p_td
.raw
);
781 RAW_encode(p_td
, root
);
782 root
.put_to_buf(p_buf
);
784 case TTCN_EncDec::CT_TEXT
: {
785 TTCN_EncDec_ErrorContext
ec("While TEXT-encoding type '%s': ", p_td
.name
);
787 TTCN_EncDec_ErrorContext::error_internal
788 ("No TEXT descriptor available for type '%s'.", p_td
.name
);
789 TEXT_encode(p_td
,p_buf
);
791 case TTCN_EncDec::CT_XER
: {
792 TTCN_EncDec_ErrorContext
ec("While XER-encoding type '%s': ", p_td
.name
);
793 unsigned XER_coding
=va_arg(pvar
, unsigned);
794 XER_encode(*p_td
.xer
, p_buf
, XER_coding
, 0, 0);
797 case TTCN_EncDec::CT_JSON
: {
798 TTCN_EncDec_ErrorContext
ec("While JSON-encoding type '%s': ", p_td
.name
);
800 TTCN_EncDec_ErrorContext::error_internal
801 ("No JSON descriptor available for type '%s'.", p_td
.name
);
802 JSON_Tokenizer
tok(va_arg(pvar
, int) != 0);
803 JSON_encode(p_td
, tok
);
804 p_buf
.put_s(tok
.get_buffer_length(), (const unsigned char*)tok
.get_buffer());
807 TTCN_error("Unknown coding method requested to encode type '%s'",
813 void CHARSTRING::decode(const TTCN_Typedescriptor_t
& p_td
,
815 TTCN_EncDec::coding_t p_coding
, ...)
818 va_start(pvar
, p_coding
);
820 case TTCN_EncDec::CT_BER
: {
821 TTCN_EncDec_ErrorContext
ec("While BER-decoding type '%s': ", p_td
.name
);
822 unsigned L_form
=va_arg(pvar
, unsigned);
824 BER_decode_str2TLV(p_buf
, tlv
, L_form
);
825 BER_decode_TLV(p_td
, tlv
, L_form
);
826 if(tlv
.isComplete
) p_buf
.increase_pos(tlv
.get_len());
828 case TTCN_EncDec::CT_RAW
: {
829 TTCN_EncDec_ErrorContext
ec("While RAW-decoding type '%s': ", p_td
.name
);
831 TTCN_EncDec_ErrorContext::error_internal
832 ("No RAW descriptor available for type '%s'.", p_td
.name
);
834 switch(p_td
.raw
->top_bit_order
){
842 if(RAW_decode(p_td
, p_buf
, p_buf
.get_len()*8, order
)<0)
843 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
844 "Can not decode type '%s', because invalid or incomplete"
845 " message was received"
848 case TTCN_EncDec::CT_TEXT
: {
849 Limit_Token_List limit
;
850 TTCN_EncDec_ErrorContext
ec("While TEXT-decoding type '%s': ", p_td
.name
);
852 TTCN_EncDec_ErrorContext::error_internal
853 ("No TEXT descriptor available for type '%s'.", p_td
.name
);
854 const unsigned char *b
=p_buf
.get_data();
855 if(b
[p_buf
.get_len()-1]!='\0'){
856 p_buf
.set_pos(p_buf
.get_len());
857 p_buf
.put_zero(8,ORDER_LSB
);
860 if(TEXT_decode(p_td
,p_buf
,limit
)<0)
861 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
862 "Can not decode type '%s', because invalid or incomplete"
863 " message was received"
866 case TTCN_EncDec::CT_XER
: {
867 TTCN_EncDec_ErrorContext
ec("While XER-decoding type '%s': ", p_td
.name
);
868 unsigned XER_coding
=va_arg(pvar
, unsigned);
869 XmlReaderWrap
reader(p_buf
);
870 int success
= reader
.Read();
871 for (; success
==1; success
=reader
.Read()) {
872 int type
= reader
.NodeType();
873 if (type
==XML_READER_TYPE_ELEMENT
)
876 XER_decode(*p_td
.xer
, reader
, XER_coding
, XER_NONE
, 0);
877 size_t bytes
= reader
.ByteConsumed();
878 p_buf
.set_pos(bytes
);
880 case TTCN_EncDec::CT_JSON
: {
881 TTCN_EncDec_ErrorContext
ec("While JSON-decoding type '%s': ", p_td
.name
);
883 TTCN_EncDec_ErrorContext::error_internal
884 ("No JSON descriptor available for type '%s'.", p_td
.name
);
885 JSON_Tokenizer
tok((const char*)p_buf
.get_data(), p_buf
.get_len());
886 if(JSON_decode(p_td
, tok
, false)<0)
887 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
888 "Can not decode type '%s', because invalid or incomplete"
889 " message was received"
891 p_buf
.set_pos(tok
.get_buf_pos());
894 TTCN_error("Unknown coding method requested to decode type '%s'",
901 CHARSTRING::BER_encode_TLV(const TTCN_Typedescriptor_t
& p_td
,
902 unsigned p_coding
) const
905 ASN_BER_TLV_t
*new_tlv
=BER_encode_chk_bound(is_bound());
907 new_tlv
=BER_encode_TLV_OCTETSTRING
908 (p_coding
, val_ptr
->n_chars
,
909 (const unsigned char*)val_ptr
->chars_ptr
);
911 new_tlv
=ASN_BER_V2TLV(new_tlv
, p_td
, p_coding
);
915 boolean
CHARSTRING::BER_decode_TLV(const TTCN_Typedescriptor_t
& p_td
,
916 const ASN_BER_TLV_t
& p_tlv
,
921 ASN_BER_TLV_t stripped_tlv
;
922 BER_decode_strip_tags(*p_td
.ber
, p_tlv
, L_form
, stripped_tlv
);
923 TTCN_EncDec_ErrorContext
ec("While decoding CHARSTRING type: ");
924 /* Upper estimation for the length. */
925 size_t stripped_tlv_len
= stripped_tlv
.get_len();
926 if (stripped_tlv_len
< 2) return FALSE
;
927 int max_len
= stripped_tlv_len
- 2;
928 init_struct(max_len
);
929 unsigned int octetnum_start
= 0;
930 BER_decode_TLV_OCTETSTRING(stripped_tlv
, L_form
, octetnum_start
,
932 (unsigned char*)val_ptr
->chars_ptr
);
933 if (val_ptr
->n_chars
< max_len
) {
934 if (val_ptr
->n_chars
== 0) {
938 val_ptr
= (charstring_struct
*)
939 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
));
940 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
946 int CHARSTRING::TEXT_decode(const TTCN_Typedescriptor_t
& p_td
,
947 TTCN_Buffer
& buff
, Limit_Token_List
& limit
, boolean no_err
, boolean
/*first_call*/)
949 int decoded_length
= 0;
952 if (p_td
.text
->begin_decode
) {
954 if ((tl
= p_td
.text
->begin_decode
->match_begin(buff
)) < 0) {
955 if (no_err
) return -1;
956 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR
,
957 "The specified token '%s' not found for '%s': ",
958 (const char*) *(p_td
.text
->begin_decode
), p_td
.name
);
961 decoded_length
+= tl
;
962 buff
.increase_pos(tl
);
964 // never return "not enough bits"
965 // if(buff.get_read_len()<=1 && no_err) return -TTCN_EncDec::ET_LEN_ERR;
967 if (p_td
.text
->select_token
) {
969 if ((tl
= p_td
.text
->select_token
->match_begin(buff
)) < 0) {
970 if (no_err
) return -1;
975 else if ( p_td
.text
->val
.parameters
976 && p_td
.text
->val
.parameters
->decoding_params
.min_length
!= -1) {
977 str_len
= p_td
.text
->val
.parameters
->decoding_params
.min_length
;
979 else if (p_td
.text
->end_decode
) {
981 if ((tl
= p_td
.text
->end_decode
->match_first(buff
)) < 0) {
982 if (no_err
) return -1;
987 else if (limit
.has_token()) {
989 if ((tl
= limit
.match(buff
)) < 0) tl
= buff
.get_read_len() - 1;
993 str_len
= buff
.get_read_len() - 1;
996 init_struct(str_len
);
997 memcpy(val_ptr
->chars_ptr
, buff
.get_read_data(), str_len
);
998 decoded_length
+= str_len
;
999 buff
.increase_pos(str_len
);
1001 if ( p_td
.text
->val
.parameters
1002 && p_td
.text
->val
.parameters
->decoding_params
.convert
!= 0) {
1003 if (p_td
.text
->val
.parameters
->decoding_params
.convert
== 1) {
1004 for (int a
= 0; a
< str_len
; a
++) {
1005 val_ptr
->chars_ptr
[a
] = toupper(val_ptr
->chars_ptr
[a
]);
1009 for (int a
= 0; a
< str_len
; a
++) {
1010 val_ptr
->chars_ptr
[a
] = tolower(val_ptr
->chars_ptr
[a
]);
1014 if (p_td
.text
->end_decode
) {
1016 if ((tl
= p_td
.text
->end_decode
->match_begin(buff
)) < 0) {
1017 if (no_err
) return -1;
1018 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR
,
1019 "The specified token '%s' not found for '%s': ",
1020 (const char*) *(p_td
.text
->end_decode
), p_td
.name
);
1023 decoded_length
+= tl
;
1024 buff
.increase_pos(tl
);
1026 return decoded_length
;
1029 int CHARSTRING::TEXT_encode(const TTCN_Typedescriptor_t
& p_td
,
1030 TTCN_Buffer
& buff
) const{
1031 int encoded_length
=0;
1032 if(p_td
.text
->begin_encode
){
1033 buff
.put_cs(*p_td
.text
->begin_encode
);
1034 encoded_length
+=p_td
.text
->begin_encode
->lengthof();
1037 TTCN_EncDec_ErrorContext::error
1038 (TTCN_EncDec::ET_UNBOUND
, "Encoding an unbound value.");
1039 if(p_td
.text
->end_encode
){
1040 buff
.put_cs(*p_td
.text
->end_encode
);
1041 encoded_length
+=p_td
.text
->end_encode
->lengthof();
1043 return encoded_length
;
1046 if(p_td
.text
->val
.parameters
==NULL
){
1048 encoded_length
+=val_ptr
->n_chars
;
1052 if(val_ptr
->n_chars
<p_td
.text
->val
.parameters
->coding_params
.min_length
){
1053 switch(p_td
.text
->val
.parameters
->coding_params
.just
){
1055 chars_after
=p_td
.text
->
1056 val
.parameters
->coding_params
.min_length
-val_ptr
->n_chars
;
1060 val
.parameters
->coding_params
.min_length
-val_ptr
->n_chars
;
1062 chars_before
=pad
-chars_after
;
1067 chars_before
=p_td
.text
->
1068 val
.parameters
->coding_params
.min_length
-val_ptr
->n_chars
;
1073 unsigned char* p
=NULL
;
1074 size_t len
=chars_before
;
1075 buff
.get_end(p
,len
);
1076 for(int a
=0;a
<chars_before
;a
++) p
[a
]=(unsigned char)' ';
1077 buff
.increase_length(chars_before
);
1078 encoded_length
+=chars_before
;
1081 switch(p_td
.text
->val
.parameters
->coding_params
.convert
){
1082 case -1:{ //lower_case
1083 unsigned char* p
=NULL
;
1084 size_t len
=val_ptr
->n_chars
;
1085 buff
.get_end(p
,len
);
1086 for(int a
=0;a
<val_ptr
->n_chars
;a
++)
1087 p
[a
]=(unsigned char)tolower(val_ptr
->chars_ptr
[a
]);
1088 buff
.increase_length(val_ptr
->n_chars
);
1091 case 0:{ // no conversion
1095 case 1: // upper_case
1098 unsigned char* p
=NULL
;
1099 size_t len
=val_ptr
->n_chars
;
1100 buff
.get_end(p
,len
);
1101 for(int a
=0;a
<val_ptr
->n_chars
;a
++)
1102 p
[a
]=(unsigned char)toupper(val_ptr
->chars_ptr
[a
]);
1103 buff
.increase_length(val_ptr
->n_chars
);
1107 encoded_length
+=val_ptr
->n_chars
;
1110 unsigned char* p
=NULL
;
1111 size_t len
=chars_after
;
1112 buff
.get_end(p
,len
);
1113 for(int a
=0;a
<chars_after
;a
++) p
[a
]=(unsigned char)' ';
1114 buff
.increase_length(chars_after
);
1115 encoded_length
+=chars_after
;
1120 if(p_td
.text
->end_encode
){
1121 buff
.put_cs(*p_td
.text
->end_encode
);
1122 encoded_length
+=p_td
.text
->end_encode
->lengthof();
1124 return encoded_length
;
1127 #ifdef TITAN_RUNTIME_2
1128 int CHARSTRING::encode_raw(TTCN_Buffer
& p_buf
) const
1130 p_buf
.put_string(*this);
1131 return val_ptr
? val_ptr
->n_chars
: 0;
1134 int CHARSTRING::JSON_encode_negtest_raw(JSON_Tokenizer
& p_tok
) const
1136 if (val_ptr
!= NULL
) {
1137 p_tok
.put_raw_data(val_ptr
->chars_ptr
, val_ptr
->n_chars
);
1138 return val_ptr
->n_chars
;
1145 void xml_escape(const unsigned int masked_c
, TTCN_Buffer
& p_buf
)
1148 // length of the majority of the names of control characters, +3 for </>
1149 static const char *escapes
[32] = {
1150 "<nul/>","<soh/>","<stx/>","<etx/>","<eot/>","<enq/>","<ack/>","<bel/>",
1151 "<bs/>" ,"<tab/>","<lf/>" ,"<vt/>" ,"<ff/>" ,"<cr/>" ,"<so/>" ,"<si/>" ,
1152 "<dle/>","<dc1/>","<dc2/>","<dc3/>","<dc4/>","<nak/>","<syn/>","<etb/>",
1153 "<can/>","<em/>" ,"<sub/>","<esc/>","<is4/>","<is3/>","<is2/>","<is1/>",
1155 unsigned int c
= (masked_c
& 0x7FFFFFFF); // unmasked
1158 // XML's "own" characters, escaped according to X.680/2002, 11.15.4 b)
1160 p_buf
.put_s(4, (cbyte
*)"<");
1164 p_buf
.put_s(4, (cbyte
*)">");
1168 p_buf
.put_s(5, (cbyte
*)"&");
1171 // Control characters, escaped according to X.680/2002, 11.15.5
1172 case 8: case 11: case 12: case 14: case 15: case 25:
1173 // the name of these control characters has only two letters
1176 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
1177 case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23:
1178 case 24: case 26: case 27: case 28: case 29: case 30: case 31:
1179 // 9=TAB 10=LF 13=CR are absent from this block altogether
1180 p_buf
.put_s(len
, (cbyte
*)escapes
[c
]);
1183 case '\"': // HR58225
1184 p_buf
.put_s(6, (cbyte
*)""");
1187 case '\'': // X.693 20.3.13: Titan uses single quotes for attributes;
1188 // so if they appear in content they must be escaped.
1189 // Currently this happens even if the string is not an attribute.
1190 p_buf
.put_s(6, (cbyte
*)"'");
1193 case 9: case 10: case 13:
1194 c
= masked_c
; // put the mask back on (makes it >127)
1197 if (c
> 127) { // XML numeric entity, as in X.680/2002 11.15.8
1198 c
&= 0x7FFFFFFF; // take it off again
1199 // Ensure that an even number of hex digits is produced
1200 int width
= (1 + (c
> 0xFF) + (c
> 0xFFFF) + (c
> 0xFFFFFF)) << 1;
1202 len
= snprintf(escapade
, 16, "&#x%0*X;", width
, c
);
1203 p_buf
.put_s(len
, (cbyte
*)(escapade
+0));
1205 else { // a plain old, unmolested character
1212 // Base64 encoder table
1213 extern const char cb64
[]=
1214 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1216 int CHARSTRING::XER_encode(const XERdescriptor_t
& p_td
,
1217 TTCN_Buffer
& p_buf
, unsigned int flavor
, int indent
, embed_values_enc_struct_t
*) const
1220 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
1221 "Encoding an unbound character string value.");
1223 int exer
= is_exer(flavor
|= SIMPLE_TYPE
);
1224 // SIMPLE_TYPE has no influence on is_exer, we set it for later
1225 int encoded_length
=(int)p_buf
.get_len();
1226 bool do_empty_element
= val_ptr
==NULL
|| val_ptr
->n_chars
== 0;
1228 flavor
&= ~XER_RECOF
; // charstring doesn't care
1230 if (do_empty_element
&& exer
&& p_td
.dfeValue
!= 0) {
1231 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_REPR
,
1232 "An encoded value with DEFAULT-FOR-EMPTY instruction applied should not be empty");
1234 if (begin_xml(p_td
, p_buf
, flavor
, indent
, do_empty_element
) == -1) {
1235 --encoded_length
; // it was shortened by one
1238 if (!do_empty_element
) {
1239 const char * current
= val_ptr
->chars_ptr
;
1240 const char * const end
= val_ptr
->chars_ptr
+ val_ptr
->n_chars
;
1241 const char * to_escape
;
1243 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
1244 to_escape
= "<&>'\"\x09\x0A\x0D";
1245 mask
= 0x80000000; // guaranteed bigger than any Unicode character
1248 to_escape
= "<&>'\"";
1252 // If Base64 is needed, use a temporary buffer.
1253 TTCN_Buffer tmpbuf
, &rbuf
= (exer
&& (p_td
.xer_bits
& BASE_64
)) ? tmpbuf
: p_buf
;
1255 // This here is an optimization. Only <&> need to be escaped.
1256 // Contiguous runs of "ordinary" characters are put in the buffer
1257 // with a single call.
1258 // TODO: is it really faster ? strpbrk is probably O(nm)
1259 while ( const char * trouble
= strpbrk(current
, to_escape
) ) {
1260 rbuf
.put_s((size_t)(trouble
- current
), (cbyte
*)current
);
1261 xml_escape(*trouble
| mask
, rbuf
); // escape the troublesome character
1262 current
= trouble
+1;
1265 // put the remainder in the buffer
1266 rbuf
.put_s( (size_t)(end
- current
), (cbyte
*)current
);
1268 if (exer
&& (p_td
.xer_bits
& BASE_64
)) {
1269 size_t clear_len
= tmpbuf
.get_len(); // the length before padding
1270 // Pad the temporary buffer so i+1 and i+2 don't go outside the buffer
1271 unsigned char zero
[2] = {0,0};
1272 tmpbuf
.put_s(2, zero
);
1273 // Get the buffer after the possible realloc caused by the padding.
1274 cbyte
* in
= tmpbuf
.get_data();
1276 // Encode 3 bytes of cleartext into 4 bytes of Base64
1277 for (size_t i
= 0; i
< clear_len
; i
+= 3) {
1278 p_buf
.put_c( cb64
[ in
[i
] >> 2 ] );
1279 p_buf
.put_c( cb64
[ ((in
[i
] & 0x03) << 4) | ((in
[i
+1] & 0xf0) >> 4) ]);
1280 p_buf
.put_c( i
+1 < clear_len
1281 ? cb64
[ ((in
[i
+1] & 0x0f) << 2) | ((in
[i
+2] & 0xc0) >> 6) ]
1283 p_buf
.put_c( i
+2 < clear_len
? cb64
[ in
[i
+2] & 0x3f ] : '=' );
1288 end_xml(p_td
, p_buf
, flavor
, indent
, do_empty_element
);
1289 return (int)p_buf
.get_len() - encoded_length
;
1293 * Translates a Base64 value to either its 6-bit reconstruction value
1294 * or a negative number indicating some other meaning.
1295 * Public domain from http://iharder.net/base64 */
1296 char base64_decoder_table
[256] =
1298 -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
1299 -5,-5, // Whitespace: Tab and Linefeed
1300 -9,-9, // Decimal 11 - 12
1301 -5, // Whitespace: Carriage Return
1302 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
1303 -9,-9,-9,-9,-9, // Decimal 27 - 31
1304 -5, // Whitespace: Space
1305 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
1306 62, // Plus sign at decimal 43
1307 -9,-9,-9, // Decimal 44 - 46
1308 63, // Slash at decimal 47
1309 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
1310 -9,-9,-9, // Decimal 58 - 60
1311 -1, // Equals sign at decimal 61
1312 -9,-9,-9, // Decimal 62 - 64
1313 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
1314 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
1315 -9,-9,-9,-9,-9,-9, // Decimal 91 - 96
1316 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
1317 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
1318 -9,-9,-9,-9,-9 // Decimal 123 - 127
1319 ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
1320 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
1321 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
1322 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
1323 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
1324 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
1325 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
1326 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
1327 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
1328 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
1331 unsigned int xlate(cbyte
*in
, int phase
, unsigned char*dest
) {
1332 static unsigned char nbytes
[4] = { 3,1,1,2 };
1333 unsigned char out
[4];
1334 out
[0] = in
[0] << 2 | in
[1] >> 4;
1335 out
[1] = in
[1] << 4 | in
[2] >> 2;
1336 out
[2] = in
[2] << 6 | in
[3] >> 0;
1337 memcpy(dest
, out
, nbytes
[phase
]);
1338 return nbytes
[phase
];
1341 int CHARSTRING::XER_decode(const XERdescriptor_t
& p_td
, XmlReaderWrap
& reader
,
1342 unsigned int flavor
, unsigned int /*flavor2*/, embed_values_dec_struct_t
*) {
1343 int exer
= is_exer(flavor
);
1344 int success
= reader
.Ok(), depth
= -1;
1346 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
1347 const char * name
= verify_name(reader
, p_td
, exer
);
1349 const char * value
= (const char *)reader
.Value();
1350 // FIXME copy & paste
1353 // Let the caller do reader.AdvanceAttribute();
1356 bool omit_tag
= exer
1357 && (p_td
.xer_bits
& UNTAGGED
|| flavor
& (EMBED_VALUES
|XER_LIST
|USE_TYPE_ATTR
|USE_NIL
));
1358 for (; success
== 1; success
= reader
.Read()) {
1359 int type
= reader
.NodeType();
1360 if (XML_READER_TYPE_ELEMENT
== type
) {
1361 verify_name(reader
, p_td
, exer
);
1362 if (reader
.IsEmptyElement()) { // has no text, needs special processing
1363 if (exer
&& p_td
.dfeValue
!= 0) {
1364 *this = *static_cast<const CHARSTRING
*>(p_td
.dfeValue
);
1366 else init_struct(0);
1368 break; // exit the loop early
1369 } // if empty element
1370 // otherwise, not an empty element, stay in the loop
1371 depth
= reader
.Depth();
1373 else if ((depth
!= -1 || omit_tag
)
1374 && (XML_READER_TYPE_TEXT
== type
|| XML_READER_TYPE_CDATA
== type
))
1375 // Process #text node if we already processed the element node, or
1376 // there is no element node because UNTAGGED is in effect.
1378 const xmlChar
* value
= reader
.Value();
1379 size_t num_chars
= strlen((const char*)value
);
1381 if (exer
&& (p_td
.xer_bits
& BASE_64
)) {
1383 init_struct(num_chars
* 3 / 4);
1387 unsigned char * dest
= (unsigned char *)val_ptr
->chars_ptr
;
1389 for (size_t o
=0; o
<num_chars
; ++o
) {
1390 xmlChar c
= value
[o
];
1391 if(c
== '=') { // Padding starts; decode last chunk and exit.
1392 dest
+= xlate(in
,phase
, dest
);
1396 int val
= base64_decoder_table
[c
];
1399 phase
= (phase
+ 1) % 4;
1401 dest
+= xlate(in
,phase
, dest
);
1402 in
[0]=in
[1]=in
[2]=in
[3]=0;
1405 else if (exer
&& (flavor
& EXIT_ON_ERROR
)) {
1409 TTCN_EncDec_ErrorContext::warning(
1410 /* if this was an error... TTCN_EncDec::ET_INVAL_MSG,*/
1411 "Invalid character for Base64 '%02X'", c
);
1415 val_ptr
->n_chars
= (char*)dest
- val_ptr
->chars_ptr
;
1419 init_struct(num_chars
);
1420 memcpy(val_ptr
->chars_ptr
, value
, num_chars
);
1424 // find the end element
1425 for (success
= reader
.Read(); success
== 1; success
= reader
.Read()) {
1426 type
= reader
.NodeType();
1427 if (XML_READER_TYPE_END_ELEMENT
== type
) {
1428 verify_end(reader
, p_td
, depth
, exer
);
1429 reader
.Read(); // one last time
1436 else if (XML_READER_TYPE_END_ELEMENT
== type
) {
1438 verify_end(reader
, p_td
, depth
, exer
);
1440 // We are at our end tag and no content
1441 if (exer
&& p_td
.dfeValue
!= 0) {
1442 *this = *static_cast<const CHARSTRING
*>(p_td
.dfeValue
);
1444 else init_struct(0); // empty string
1453 if (exer
&& p_td
.whitespace
>= WHITESPACE_REPLACE
) { // includes _COLLAPSE
1454 for (int i
=0; i
<val_ptr
->n_chars
; ++i
) { // first, _REPLACE
1455 switch (val_ptr
->chars_ptr
[i
]) {
1456 case 9: // HORIZONTAL TAB
1457 case 10: // LINE FEED
1458 case 13: // CARRIAGE RETURN
1459 val_ptr
->chars_ptr
[i
] = ' ';
1466 if (p_td
.whitespace
>= WHITESPACE_COLLAPSE
) {
1468 const char *from
, *end
= val_ptr
->chars_ptr
+ val_ptr
->n_chars
;
1469 for (from
= to
= val_ptr
->chars_ptr
; from
< end
;) {
1471 // If the copied character (*to) was a space,
1472 // and the next character to be copied (*from) is also a space
1473 // (continuous run of spaces)
1474 // or this was the first character (leading spaces to be trimmed),
1475 // then don't advance the destination (will be overwritten).
1477 || (from
< end
&& *from
!= ' ' && to
> val_ptr
->chars_ptr
)) ++to
;
1480 val_ptr
->n_chars
= to
- val_ptr
->chars_ptr
; // truncate
1481 // TODO maybe realloc after truncation
1488 int CHARSTRING::RAW_encode(const TTCN_Typedescriptor_t
& p_td
,
1489 RAW_enc_tree
& myleaf
) const
1491 int bl
= val_ptr
->n_chars
* 8; // bit length
1492 int align_length
= p_td
.raw
->fieldlength
? p_td
.raw
->fieldlength
- bl
: 0;
1494 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
1495 "Encoding an unbound value.");
1497 if ((bl
+ align_length
) < val_ptr
->n_chars
* 8) {
1498 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
1499 "There is no sufficient bits to encode '%s': ", p_td
.name
);
1500 bl
= p_td
.raw
->fieldlength
;
1503 if (myleaf
.must_free
) Free(myleaf
.body
.leaf
.data_ptr
);
1504 myleaf
.must_free
= FALSE
;
1505 myleaf
.data_ptr_used
= TRUE
;
1506 myleaf
.body
.leaf
.data_ptr
= (unsigned char*) val_ptr
->chars_ptr
;
1507 if (p_td
.raw
->endianness
== ORDER_MSB
) myleaf
.align
= -align_length
;
1508 else myleaf
.align
= align_length
;
1509 return myleaf
.length
= bl
+ align_length
;
1512 int CHARSTRING::RAW_decode(const TTCN_Typedescriptor_t
& p_td
,
1513 TTCN_Buffer
& buff
, int limit
, raw_order_t top_bit_ord
, boolean no_err
,
1514 int /*sel_field*/, boolean
/*first_call*/)
1516 int prepaddlength
= buff
.increase_pos_padd(p_td
.raw
->prepadding
);
1517 limit
-= prepaddlength
;
1518 int decode_length
= p_td
.raw
->fieldlength
== 0
1519 ? (limit
/ 8) * 8 : p_td
.raw
->fieldlength
;
1520 if ( decode_length
> limit
1521 || decode_length
> (int) buff
.unread_len_bit()) {
1522 if (no_err
) return -TTCN_EncDec::ET_LEN_ERR
;
1523 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
1524 "There is not enough bits in the buffer to decode type %s.", p_td
.name
);
1525 decode_length
= ((limit
> (int) buff
.unread_len_bit() ? (int)buff
.unread_len_bit() : limit
) / 8) * 8;
1528 boolean orders
= FALSE
;
1529 if (p_td
.raw
->bitorderinoctet
== ORDER_MSB
) orders
= TRUE
;
1530 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
1531 cp
.bitorder
= orders
? ORDER_MSB
: ORDER_LSB
;
1533 if (p_td
.raw
->byteorder
== ORDER_MSB
) orders
= TRUE
;
1534 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
1535 cp
.byteorder
= orders
? ORDER_MSB
: ORDER_LSB
;
1536 cp
.fieldorder
= p_td
.raw
->fieldorder
;
1537 cp
.hexorder
= ORDER_LSB
;
1539 init_struct(decode_length
/ 8);
1540 buff
.get_b((size_t) decode_length
, (unsigned char*) val_ptr
->chars_ptr
, cp
,
1543 if (p_td
.raw
->length_restrition
!= -1) {
1544 val_ptr
->n_chars
= p_td
.raw
->length_restrition
;
1545 if (p_td
.raw
->endianness
== ORDER_MSB
) memmove(val_ptr
->chars_ptr
,
1546 val_ptr
->chars_ptr
+ (decode_length
/ 8 - val_ptr
->n_chars
),
1547 val_ptr
->n_chars
); // sizeof(char) == 1 by definition
1549 decode_length
+= buff
.increase_pos_padd(p_td
.raw
->padding
);
1550 return decode_length
+ prepaddlength
;
1553 char* CHARSTRING::to_JSON_string() const
1555 // Need at least 3 more characters (the double quotes around the string and the terminating zero)
1556 char* json_str
= (char*)Malloc(val_ptr
->n_chars
+ 3);
1559 json_str
= mputc(json_str
, '\"');
1561 for (int i
= 0; i
< val_ptr
->n_chars
; ++i
) {
1562 // Increase the size of the buffer if it's not big enough to store the
1563 // characters remaining in the charstring plus 1 (for safety, in case this
1564 // character needs to be double-escaped).
1565 switch(val_ptr
->chars_ptr
[i
]) {
1567 json_str
= mputstrn(json_str
, "\\\\", 2);
1570 json_str
= mputstrn(json_str
, "\\n", 2);
1573 json_str
= mputstrn(json_str
, "\\t", 2);
1576 json_str
= mputstrn(json_str
, "\\r", 2);
1579 json_str
= mputstrn(json_str
, "\\f", 2);
1582 json_str
= mputstrn(json_str
, "\\b", 2);
1585 json_str
= mputstrn(json_str
, "\\\"", 2);
1588 json_str
= mputc(json_str
, val_ptr
->chars_ptr
[i
]);
1593 json_str
= mputc(json_str
, '\"');
1597 boolean
CHARSTRING::from_JSON_string(const char* p_value
, size_t p_value_len
, boolean check_quotes
)
1600 size_t end
= p_value_len
;
1603 end
= p_value_len
- 1;
1604 if (p_value
[0] != '\"' || p_value
[p_value_len
- 1] != '\"') {
1609 // The charstring will be shorter than the JSON string, at least by the 2 quotes
1610 char* str
= (char*)Malloc(end
- start
);
1612 boolean error
= false;
1614 for (size_t i
= start
; i
< end
; ++i
) {
1615 if (0 > p_value
[i
]) {
1619 if ('\\' == p_value
[i
]) {
1624 switch(p_value
[i
+ 1]) {
1650 if (end
- i
>= 6 && '0' == p_value
[i
+ 2] && '0' == p_value
[i
+ 3]) {
1651 unsigned char upper_nibble
= char_to_hexdigit(p_value
[i
+ 4]);
1652 unsigned char lower_nibble
= char_to_hexdigit(p_value
[i
+ 5]);
1653 if (0x07 >= upper_nibble
&& 0x0F >= lower_nibble
) {
1654 str
[len
++] = (upper_nibble
<< 4) | lower_nibble
;
1655 // skip 4 extra characters (the 4 hex digits)
1658 // error (found something other than hex digits) -> leave the for cycle
1663 // error (not enough characters left or the first 2 hex digits are non-null) -> leave the for cycle
1670 // error (invalid escaped character) -> leave the for cycle
1675 // skip an extra character (the \)
1678 str
[len
++] = p_value
[i
];
1681 if (check_quotes
&& i
== p_value_len
- 1) {
1682 // Special case: the last 2 characters are double escaped quotes ('\\' and '\"')
1690 memcpy(val_ptr
->chars_ptr
, str
, len
);
1691 val_ptr
->chars_ptr
[len
] = 0;
1697 int CHARSTRING::JSON_encode(const TTCN_Typedescriptor_t
&, JSON_Tokenizer
& p_tok
) const
1700 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
1701 "Encoding an unbound charstring value.");
1705 char* tmp_str
= to_JSON_string();
1706 int enc_len
= p_tok
.put_next_token(JSON_TOKEN_STRING
, tmp_str
);
1711 int CHARSTRING::JSON_decode(const TTCN_Typedescriptor_t
& p_td
, JSON_Tokenizer
& p_tok
, boolean p_silent
)
1713 json_token_t token
= JSON_TOKEN_NONE
;
1715 size_t value_len
= 0;
1717 boolean use_default
= p_td
.json
->default_value
&& 0 == p_tok
.get_buffer_length();
1719 // No JSON data in the buffer -> use default value
1720 value
= (char*)p_td
.json
->default_value
;
1721 value_len
= strlen(value
);
1723 dec_len
= p_tok
.get_next_token(&token
, &value
, &value_len
);
1725 if (JSON_TOKEN_ERROR
== token
) {
1726 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_BAD_TOKEN_ERROR
, "");
1727 return JSON_ERROR_FATAL
;
1729 else if (JSON_TOKEN_STRING
== token
|| use_default
) {
1730 if (!from_JSON_string(value
, value_len
, !use_default
)) {
1731 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_FORMAT_ERROR
, "string", "charstring");
1733 return JSON_ERROR_FATAL
;
1736 return JSON_ERROR_INVALID_TOKEN
;
1742 CHARSTRING_ELEMENT::CHARSTRING_ELEMENT(boolean par_bound_flag
,
1743 CHARSTRING
& par_str_val
, int par_char_pos
)
1744 : bound_flag(par_bound_flag
), str_val(par_str_val
), char_pos(par_char_pos
)
1749 CHARSTRING_ELEMENT
& CHARSTRING_ELEMENT::operator=(const char* other_value
)
1751 if (other_value
== NULL
||
1752 other_value
[0] == '\0' || other_value
[1] != '\0')
1753 TTCN_error("Assignment of a charstring value with length other "
1754 "than 1 to a charstring element.");
1756 str_val
.copy_value();
1757 str_val
.val_ptr
->chars_ptr
[char_pos
] = other_value
[0];
1761 CHARSTRING_ELEMENT
& CHARSTRING_ELEMENT::operator=
1762 (const CHARSTRING
& other_value
)
1764 other_value
.must_bound("Assignment of an unbound charstring value to a "
1765 "charstring element.");
1766 if(other_value
.val_ptr
->n_chars
!= 1)
1767 TTCN_error("Assignment of a charstring value with length other than "
1768 "1 to a charstring element.");
1770 str_val
.copy_value();
1771 str_val
.val_ptr
->chars_ptr
[char_pos
] = other_value
.val_ptr
->chars_ptr
[0];
1775 CHARSTRING_ELEMENT
& CHARSTRING_ELEMENT::operator=
1776 (const CHARSTRING_ELEMENT
& other_value
)
1778 other_value
.must_bound("Assignment of an unbound charstring element.");
1779 if (&other_value
!= this) {
1781 str_val
.copy_value();
1782 str_val
.val_ptr
->chars_ptr
[char_pos
] =
1783 other_value
.str_val
.val_ptr
->chars_ptr
[other_value
.char_pos
];
1788 boolean
CHARSTRING_ELEMENT::operator==(const char *other_value
) const
1790 must_bound("Comparison of an unbound charstring element.");
1791 if (other_value
== NULL
|| other_value
[0] == '\0' ||
1792 other_value
[1] != '\0') return FALSE
;
1793 return str_val
.val_ptr
->chars_ptr
[char_pos
] == other_value
[0];
1796 boolean
CHARSTRING_ELEMENT::operator==(const CHARSTRING
& other_value
) const
1798 must_bound("Comparison of an unbound charstring element.");
1799 other_value
.must_bound("Comparison of an unbound charstring value.");
1800 if (other_value
.val_ptr
->n_chars
!= 1) return FALSE
;
1801 return str_val
.val_ptr
->chars_ptr
[char_pos
] ==
1802 other_value
.val_ptr
->chars_ptr
[0];
1805 boolean
CHARSTRING_ELEMENT::operator==(const CHARSTRING_ELEMENT
& other_value
) const
1807 must_bound("Comparison of an unbound charstring element.");
1808 other_value
.must_bound("Comparison of an unbound charstring element.");
1809 return str_val
.val_ptr
->chars_ptr
[char_pos
] ==
1810 other_value
.str_val
.val_ptr
->chars_ptr
[other_value
.char_pos
];
1813 boolean
CHARSTRING_ELEMENT::operator==(const UNIVERSAL_CHARSTRING
& other_value
)
1816 must_bound("The left operand of comparison is an unbound charstring "
1818 other_value
.must_bound("The right operand of comparison is an unbound "
1819 "universal charstring value.");
1820 if (other_value
.charstring
) {
1821 if (other_value
.cstr
.val_ptr
->n_chars
!= 1) return FALSE
;
1822 return str_val
.val_ptr
->chars_ptr
[char_pos
] ==
1823 other_value
.cstr
.val_ptr
->chars_ptr
[0];
1826 if (other_value
.val_ptr
->n_uchars
!= 1) return FALSE
;
1827 return other_value
.val_ptr
->uchars_ptr
[0].uc_group
== 0 &&
1828 other_value
.val_ptr
->uchars_ptr
[0].uc_plane
== 0 &&
1829 other_value
.val_ptr
->uchars_ptr
[0].uc_row
== 0 &&
1830 other_value
.val_ptr
->uchars_ptr
[0].uc_cell
==
1831 (cbyte
)str_val
.val_ptr
->chars_ptr
[char_pos
];
1835 boolean
CHARSTRING_ELEMENT::operator==
1836 (const UNIVERSAL_CHARSTRING_ELEMENT
& other_value
) const
1838 must_bound("The left operand of comparison is an unbound charstring "
1840 other_value
.must_bound("The right operand of comparison is an unbound "
1841 "universal charstring element.");
1842 const universal_char
& uchar
= other_value
.get_uchar();
1843 return uchar
.uc_group
== 0 && uchar
.uc_plane
== 0 && uchar
.uc_row
== 0 &&
1844 uchar
.uc_cell
== (cbyte
)str_val
.val_ptr
->chars_ptr
[char_pos
];
1847 CHARSTRING
CHARSTRING_ELEMENT::operator+(const char *other_value
) const
1849 must_bound("Unbound operand of charstring element concatenation.");
1851 if (other_value
== NULL
) other_len
= 0;
1852 else other_len
= strlen(other_value
);
1853 CHARSTRING
ret_val(other_len
+ 1);
1854 ret_val
.val_ptr
->chars_ptr
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1855 memcpy(ret_val
.val_ptr
->chars_ptr
+ 1, other_value
, other_len
);
1859 CHARSTRING
CHARSTRING_ELEMENT::operator+(const CHARSTRING
& other_value
) const
1861 must_bound("Unbound operand of charstring element concatenation.");
1862 other_value
.must_bound("Unbound operand of charstring concatenation.");
1863 int n_chars
= other_value
.val_ptr
->n_chars
;
1864 CHARSTRING
ret_val(n_chars
+ 1);
1865 ret_val
.val_ptr
->chars_ptr
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1866 memcpy(ret_val
.val_ptr
->chars_ptr
+ 1, other_value
.val_ptr
->chars_ptr
,
1871 CHARSTRING
CHARSTRING_ELEMENT::operator+(const CHARSTRING_ELEMENT
&
1874 must_bound("Unbound operand of charstring element concatenation.");
1875 other_value
.must_bound("Unbound operand of charstring element "
1878 result
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1879 result
[1] = other_value
.str_val
.val_ptr
->chars_ptr
[other_value
.char_pos
];
1880 return CHARSTRING(2, result
);
1883 UNIVERSAL_CHARSTRING
CHARSTRING_ELEMENT::operator+
1884 (const UNIVERSAL_CHARSTRING
& other_value
) const
1886 must_bound("The left operand of concatenation is an unbound charstring "
1888 other_value
.must_bound("The right operand of concatenation is an unbound "
1889 "universal charstring value.");
1890 if (other_value
.charstring
) {
1891 UNIVERSAL_CHARSTRING
ret_val(other_value
.cstr
.val_ptr
->n_chars
+ 1, true);
1892 ret_val
.cstr
.val_ptr
->chars_ptr
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1893 memcpy(ret_val
.cstr
.val_ptr
->chars_ptr
+ 1, other_value
.cstr
.val_ptr
->chars_ptr
, other_value
.cstr
.val_ptr
->n_chars
);
1896 UNIVERSAL_CHARSTRING
ret_val(other_value
.val_ptr
->n_uchars
+ 1);
1897 ret_val
.val_ptr
->uchars_ptr
[0].uc_group
= 0;
1898 ret_val
.val_ptr
->uchars_ptr
[0].uc_plane
= 0;
1899 ret_val
.val_ptr
->uchars_ptr
[0].uc_row
= 0;
1900 ret_val
.val_ptr
->uchars_ptr
[0].uc_cell
= str_val
.val_ptr
->chars_ptr
[char_pos
];
1901 memcpy(ret_val
.val_ptr
->uchars_ptr
+ 1, other_value
.val_ptr
->uchars_ptr
,
1902 other_value
.val_ptr
->n_uchars
* sizeof(universal_char
));
1907 UNIVERSAL_CHARSTRING
CHARSTRING_ELEMENT::operator+
1908 (const UNIVERSAL_CHARSTRING_ELEMENT
& other_value
) const
1910 must_bound("The left operand of concatenation is an unbound charstring "
1912 other_value
.must_bound("The right operand of concatenation is an unbound "
1913 "universal charstring element.");
1914 universal_char result
[2];
1915 result
[0].uc_group
= 0;
1916 result
[0].uc_plane
= 0;
1917 result
[0].uc_row
= 0;
1918 result
[0].uc_cell
= str_val
.val_ptr
->chars_ptr
[char_pos
];
1919 result
[1] = other_value
.get_uchar();
1920 return UNIVERSAL_CHARSTRING(2, result
);
1923 char CHARSTRING_ELEMENT::get_char() const
1925 return str_val
.val_ptr
->chars_ptr
[char_pos
];
1928 void CHARSTRING_ELEMENT::log() const
1931 char c
= str_val
.val_ptr
->chars_ptr
[char_pos
];
1932 if (TTCN_Logger::is_printable(c
)) {
1933 TTCN_Logger::log_char('"');
1934 TTCN_Logger::log_char_escaped(c
);
1935 TTCN_Logger::log_char('"');
1936 } else TTCN_Logger::log_event("char(0, 0, 0, %u)", (unsigned char)c
);
1937 } else TTCN_Logger::log_event_unbound();
1942 boolean
operator==(const char* string_value
, const CHARSTRING
& other_value
)
1944 other_value
.must_bound("Unbound operand of charstring comparison.");
1945 if (string_value
== NULL
) string_value
= "";
1946 return !strcmp(string_value
, other_value
.val_ptr
->chars_ptr
);
1949 boolean
operator==(const char* string_value
,
1950 const CHARSTRING_ELEMENT
& other_value
)
1952 other_value
.must_bound("Unbound operand of charstring element "
1954 if (string_value
== NULL
|| string_value
[0] == '\0' ||
1955 string_value
[1] != '\0') return FALSE
;
1956 return string_value
[0] == other_value
.get_char();
1959 CHARSTRING
operator+(const char* string_value
, const CHARSTRING
& other_value
)
1961 other_value
.must_bound("Unbound operand of charstring concatenation.");
1963 if (string_value
== NULL
) string_len
= 0;
1964 else string_len
= strlen(string_value
);
1965 if (string_len
== 0) return other_value
;
1966 CHARSTRING
ret_val(string_len
+ other_value
.val_ptr
->n_chars
);
1967 memcpy(ret_val
.val_ptr
->chars_ptr
, string_value
, string_len
);
1968 memcpy(ret_val
.val_ptr
->chars_ptr
+ string_len
,
1969 other_value
.val_ptr
->chars_ptr
, other_value
.val_ptr
->n_chars
);
1973 CHARSTRING
operator+(const char* string_value
,
1974 const CHARSTRING_ELEMENT
& other_value
)
1976 other_value
.must_bound("Unbound operand of charstring element "
1979 if (string_value
== NULL
) string_len
= 0;
1980 else string_len
= strlen(string_value
);
1981 if (string_len
== 0) return CHARSTRING(other_value
);
1982 CHARSTRING
ret_val(string_len
+ 1);
1983 memcpy(ret_val
.val_ptr
->chars_ptr
, string_value
, string_len
);
1984 ret_val
.val_ptr
->chars_ptr
[string_len
] = other_value
.get_char();
1988 CHARSTRING
operator<<=(const char *string_value
, const INTEGER
& rotate_count
)
1990 return CHARSTRING(string_value
) <<= rotate_count
;
1993 CHARSTRING
operator>>=(const char *string_value
, const INTEGER
& rotate_count
)
1995 return CHARSTRING(string_value
) >>= rotate_count
;
1998 // charstring template class
2000 void CHARSTRING_template::clean_up()
2002 switch(template_selection
) {
2004 case COMPLEMENTED_LIST
:
2005 delete [] value_list
.list_value
;
2007 case STRING_PATTERN
:
2008 if (pattern_value
.regexp_init
) regfree(&pattern_value
.posix_regexp
);
2013 template_selection
= UNINITIALIZED_TEMPLATE
;
2016 void CHARSTRING_template::copy_template(const CHARSTRING_template
& other_value
)
2018 switch (other_value
.template_selection
) {
2019 case STRING_PATTERN
:
2020 pattern_value
.regexp_init
= FALSE
;
2022 case SPECIFIC_VALUE
:
2023 single_value
= other_value
.single_value
;
2030 case COMPLEMENTED_LIST
:
2031 value_list
.n_values
= other_value
.value_list
.n_values
;
2032 value_list
.list_value
= new CHARSTRING_template
[value_list
.n_values
];
2033 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2034 value_list
.list_value
[i
].copy_template(
2035 other_value
.value_list
.list_value
[i
]);
2038 if (!other_value
.value_range
.min_is_set
) TTCN_error("The lower bound is "
2039 "not set when copying a charstring value range template.");
2040 if (!other_value
.value_range
.max_is_set
) TTCN_error("The upper bound is "
2041 "not set when copying a charstring value range template.");
2042 value_range
= other_value
.value_range
;
2045 TTCN_error("Copying an uninitialized/unsupported charstring template.");
2047 set_selection(other_value
);
2050 CHARSTRING_template::CHARSTRING_template()
2054 CHARSTRING_template::CHARSTRING_template(template_sel other_value
)
2055 : Restricted_Length_Template(other_value
)
2057 check_single_selection(other_value
);
2060 CHARSTRING_template::CHARSTRING_template(const CHARSTRING
& other_value
)
2061 : Restricted_Length_Template(SPECIFIC_VALUE
), single_value(other_value
)
2065 CHARSTRING_template::CHARSTRING_template(const CHARSTRING_ELEMENT
& other_value
)
2066 : Restricted_Length_Template(SPECIFIC_VALUE
), single_value(other_value
)
2070 CHARSTRING_template::CHARSTRING_template(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("Creating a charstring template from an unbound optional "
2086 CHARSTRING_template::CHARSTRING_template(template_sel p_sel
,
2087 const CHARSTRING
& p_str
)
2088 : Restricted_Length_Template(STRING_PATTERN
), single_value(p_str
)
2090 if(p_sel
!=STRING_PATTERN
)
2091 TTCN_error("Internal error: Initializing a charstring pattern template "
2092 "with invalid selection.");
2093 pattern_value
.regexp_init
=FALSE
;
2096 CHARSTRING_template::CHARSTRING_template(const CHARSTRING_template
& other_value
)
2097 : Restricted_Length_Template()
2099 copy_template(other_value
);
2102 CHARSTRING_template::~CHARSTRING_template()
2107 CHARSTRING_template
& CHARSTRING_template::operator=(template_sel other_value
)
2109 check_single_selection(other_value
);
2111 set_selection(other_value
);
2115 CHARSTRING_template
& CHARSTRING_template::operator=
2116 (const CHARSTRING
& other_value
)
2118 other_value
.must_bound("Assignment of an unbound charstring value to a "
2121 set_selection(SPECIFIC_VALUE
);
2122 single_value
= other_value
;
2126 CHARSTRING_template
& CHARSTRING_template::operator=
2127 (const CHARSTRING_ELEMENT
& other_value
)
2129 other_value
.must_bound("Assignment of an unbound charstring element to a "
2132 set_selection(SPECIFIC_VALUE
);
2133 single_value
= other_value
;
2137 CHARSTRING_template
& CHARSTRING_template::operator=
2138 (const OPTIONAL
<CHARSTRING
>& other_value
)
2141 switch (other_value
.get_selection()) {
2142 case OPTIONAL_PRESENT
:
2143 set_selection(SPECIFIC_VALUE
);
2144 single_value
= (const CHARSTRING
&)other_value
;
2147 set_selection(OMIT_VALUE
);
2150 TTCN_error("Assignment of an unbound optional field to a charstring "
2156 CHARSTRING_template
& CHARSTRING_template::operator=
2157 (const CHARSTRING_template
& other_value
)
2159 if (&other_value
!= this) {
2161 copy_template(other_value
);
2166 CHARSTRING_ELEMENT
CHARSTRING_template::operator[](int index_value
)
2168 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
2169 TTCN_error("Accessing a charstring element of a non-specific charstring "
2171 return single_value
[index_value
];
2174 CHARSTRING_ELEMENT
CHARSTRING_template::operator[](const INTEGER
& index_value
)
2176 index_value
.must_bound("Indexing a charstring template with an unbound "
2178 return (*this)[(int)index_value
];
2181 const CHARSTRING_ELEMENT
CHARSTRING_template::operator[](int index_value
) const
2183 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
2184 TTCN_error("Accessing a charstring element of a non-specific charstring "
2186 return single_value
[index_value
];
2189 const CHARSTRING_ELEMENT
CHARSTRING_template::operator[](const INTEGER
& index_value
) const
2191 index_value
.must_bound("Indexing a charstring template with an unbound "
2193 return (*this)[(int)index_value
];
2196 boolean
CHARSTRING_template::match(const CHARSTRING
& other_value
,
2197 boolean
/* legacy */) const
2199 if (!other_value
.is_bound()) return FALSE
;
2200 int value_length
= other_value
.lengthof();
2201 if (!match_length(value_length
)) return FALSE
;
2202 switch (template_selection
) {
2203 case SPECIFIC_VALUE
:
2204 return single_value
== other_value
;
2205 case STRING_PATTERN
: {
2206 if (!pattern_value
.regexp_init
) {
2207 char *posix_str
=TTCN_pattern_to_regexp(single_value
);
2208 if(posix_str
==NULL
) {
2209 TTCN_error("Cannot convert pattern \"%s\" to POSIX-equivalent.",
2210 (const char*)single_value
);
2213 //TTCN_Logger::begin_event(TTCN_DEBUG);
2214 TTCN_Logger::log_event_str("POSIX ERE equivalent of pattern ");
2216 TTCN_Logger::log_event(" is: \"%s\"", posix_str);
2217 //TTCN_Logger::end_event();
2219 int ret_val
=regcomp(&pattern_value
.posix_regexp
, posix_str
,
2220 REG_EXTENDED
|REG_NOSUB
);
2224 char msg
[ERRMSG_BUFSIZE
];
2225 regerror(ret_val
, &pattern_value
.posix_regexp
, msg
, ERRMSG_BUFSIZE
);
2226 regfree(&pattern_value
.posix_regexp
);
2227 TTCN_error("Pattern matching error: %s", msg
);
2229 pattern_value
.regexp_init
=TRUE
;
2231 int ret_val
=regexec(&pattern_value
.posix_regexp
, other_value
, 0, NULL
, 0);
2239 char msg
[ERRMSG_BUFSIZE
];
2240 regerror(ret_val
, &pattern_value
.posix_regexp
, msg
, ERRMSG_BUFSIZE
);
2241 TTCN_error("Pattern matching error: %s", msg
);
2250 case COMPLEMENTED_LIST
:
2251 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2252 if (value_list
.list_value
[i
].match(other_value
))
2253 return template_selection
== VALUE_LIST
;
2254 return template_selection
== COMPLEMENTED_LIST
;
2256 if (!value_range
.min_is_set
) TTCN_error("The lower bound is not set when "
2257 "matching with a charstring value range template.");
2258 if (!value_range
.max_is_set
) TTCN_error("The upper bound is not set when "
2259 "matching with a charstring value range template.");
2260 if (value_range
.min_value
> value_range
.max_value
)
2261 TTCN_error("The lower bound (\"%c\") is greater than the upper bound "
2262 "(\"%c\") when matching with a charstring value range template.",
2263 value_range
.min_value
, value_range
.max_value
);
2264 const char *chars_ptr
= other_value
;
2265 for (int i
= 0; i
< value_length
; i
++) {
2266 if (chars_ptr
[i
] < value_range
.min_value
||
2267 chars_ptr
[i
] > value_range
.max_value
) return FALSE
;
2272 TTCN_error("Matching with an uninitialized/unsupported charstring "
2278 const CHARSTRING
& CHARSTRING_template::valueof() const
2280 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
2281 TTCN_error("Performing valueof or send operation on a non-specific "
2282 "charstring template.");
2283 return single_value
;
2286 int CHARSTRING_template::lengthof() const
2289 boolean has_any_or_none
;
2291 TTCN_error("Performing lengthof() operation on a charstring template "
2292 "which has an ifpresent attribute.");
2293 switch (template_selection
)
2295 case SPECIFIC_VALUE
:
2296 min_length
= single_value
.lengthof();
2297 has_any_or_none
= FALSE
;
2300 TTCN_error("Performing lengthof() operation on a charstring template "
2301 "containing omit value.");
2306 has_any_or_none
= TRUE
; // max. length is infinity
2310 // error if any element does not have length or the lengths differ
2311 if (value_list
.n_values
<1)
2312 TTCN_error("Internal error: "
2313 "Performing lengthof() operation on a charstring template "
2314 "containing an empty list.");
2315 int item_length
= value_list
.list_value
[0].lengthof();
2316 for (unsigned int i
= 1; i
< value_list
.n_values
; i
++) {
2317 if (value_list
.list_value
[i
].lengthof()!=item_length
)
2318 TTCN_error("Performing lengthof() operation on a charstring template "
2319 "containing a value list with different lengths.");
2321 min_length
= item_length
;
2322 has_any_or_none
= FALSE
;
2325 case COMPLEMENTED_LIST
:
2326 TTCN_error("Performing lengthof() operation on a charstring template "
2327 "containing complemented list.");
2328 case STRING_PATTERN
:
2329 TTCN_error("Performing lengthof() operation on a charstring template "
2330 "containing a pattern is not allowed.");
2332 TTCN_error("Performing lengthof() operation on an "
2333 "uninitialized/unsupported charstring template.");
2335 return check_section_is_single(min_length
, has_any_or_none
,
2336 "length", "a", "charstring template");
2339 void CHARSTRING_template::set_type(template_sel template_type
,
2340 unsigned int list_length
)
2343 switch (template_type
) {
2345 case COMPLEMENTED_LIST
:
2346 set_selection(template_type
);
2347 value_list
.n_values
= list_length
;
2348 value_list
.list_value
= new CHARSTRING_template
[list_length
];
2351 set_selection(VALUE_RANGE
);
2352 value_range
.min_is_set
= FALSE
;
2353 value_range
.max_is_set
= FALSE
;
2356 TTCN_error("Setting an invalid type for a charstring template.");
2360 CHARSTRING_template
& CHARSTRING_template::list_item(unsigned int list_index
)
2362 if (template_selection
!= VALUE_LIST
&&
2363 template_selection
!= COMPLEMENTED_LIST
)
2364 TTCN_error("Internal error: Accessing a list element of a non-list "
2365 "charstring template.");
2366 if (list_index
>= value_list
.n_values
)
2367 TTCN_error("Internal error: Index overflow in a charstring value list "
2369 return value_list
.list_value
[list_index
];
2372 void CHARSTRING_template::set_min(const CHARSTRING
& min_value
)
2374 if (template_selection
!= VALUE_RANGE
)
2375 TTCN_error("Setting the lower bound for a non-range charstring template.");
2376 min_value
.must_bound("Setting an unbound value as lower bound in a "
2377 "charstring value range template.");
2378 int length
= min_value
.lengthof();
2379 if (length
!= 1) TTCN_error("The length of the lower bound in a "
2380 "charstring value range template must be 1 instead of %d.", length
);
2381 value_range
.min_is_set
= TRUE
;
2382 value_range
.min_value
= *(const char*)min_value
;
2383 if (value_range
.max_is_set
&& value_range
.min_value
> value_range
.max_value
)
2384 TTCN_error("The lower bound (\"%c\") in a charstring value range template "
2385 "is greater than the upper bound (\"%c\").", value_range
.min_value
,
2386 value_range
.max_value
);
2389 void CHARSTRING_template::set_max(const CHARSTRING
& max_value
)
2391 if (template_selection
!= VALUE_RANGE
)
2392 TTCN_error("Setting the upper bound for a non-range charstring template.");
2393 max_value
.must_bound("Setting an unbound value as upper bound in a "
2394 "charstring value range template.");
2395 int length
= max_value
.lengthof();
2396 if (length
!= 1) TTCN_error("The length of the upper bound in a "
2397 "charstring value range template must be 1 instead of %d.", length
);
2398 value_range
.max_is_set
= TRUE
;
2399 value_range
.max_value
= *(const char*)max_value
;
2400 if (value_range
.min_is_set
&& value_range
.min_value
> value_range
.max_value
)
2401 TTCN_error("The upper bound (\"%c\") in a charstring value range template "
2402 "is smaller than the lower bound (\"%c\").", value_range
.max_value
,
2403 value_range
.min_value
);
2406 void CHARSTRING_template::log_pattern(int n_chars
, const char *chars_ptr
)
2408 TTCN_Logger::log_event_str("pattern \"");
2409 enum { INITIAL
, BACKSLASH
, BACKSLASH_Q
, QUADRUPLE
, HASHMARK
, REPETITIONS
}
2411 for (int i
= 0; i
< n_chars
; i
++) {
2412 unsigned char c
= chars_ptr
[i
];
2413 // print the character
2417 TTCN_Logger::log_event_str("\\\"");
2420 if (state
== BACKSLASH
|| state
== BACKSLASH_Q
)
2421 TTCN_Logger::log_char('{');
2422 else TTCN_Logger::log_event_str("\\{");
2425 if (state
== BACKSLASH
|| state
== QUADRUPLE
)
2426 TTCN_Logger::log_char('}');
2427 else TTCN_Logger::log_event_str("\\}");
2430 if (state
!= INITIAL
&& state
!= BACKSLASH
) break;
2433 TTCN_Logger::log_char(c
);
2439 if (state
== INITIAL
|| state
== BACKSLASH
)
2440 TTCN_Logger::log_event_str("\\t");
2443 if (state
== INITIAL
|| state
== BACKSLASH
)
2444 TTCN_Logger::log_event_str("\\r");
2449 if (state
!= INITIAL
&& state
!= BACKSLASH
) break;
2452 TTCN_Logger::log_event("\\q{0,0,0,%u}", c
);
2471 if (c
== 'q') state
= BACKSLASH_Q
;
2472 else state
= INITIAL
;
2494 state
= REPETITIONS
;
2520 if (!isdigit(c
)) state
= INITIAL
;
2526 TTCN_Logger::log_char('"');
2529 void CHARSTRING_template::log() const
2531 switch (template_selection
) {
2532 case STRING_PATTERN
:
2533 log_pattern(single_value
.lengthof(), (const char*)single_value
);
2535 case SPECIFIC_VALUE
:
2538 case COMPLEMENTED_LIST
:
2539 TTCN_Logger::log_event_str("complement ");
2542 TTCN_Logger::log_char('(');
2543 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++) {
2544 if (i
> 0) TTCN_Logger::log_event_str(", ");
2545 value_list
.list_value
[i
].log();
2547 TTCN_Logger::log_char(')');
2550 TTCN_Logger::log_char('(');
2551 if (value_range
.min_is_set
) {
2552 if (TTCN_Logger::is_printable(value_range
.min_value
)) {
2553 TTCN_Logger::log_char('"');
2554 TTCN_Logger::log_char_escaped(value_range
.min_value
);
2555 TTCN_Logger::log_char('"');
2556 } else TTCN_Logger::log_event("char(0, 0, 0, %u)",
2557 (unsigned char)value_range
.min_value
);
2558 } else TTCN_Logger::log_event_str("<unknown lower bound>");
2559 TTCN_Logger::log_event_str(" .. ");
2560 if (value_range
.max_is_set
) {
2561 if (TTCN_Logger::is_printable(value_range
.max_value
)) {
2562 TTCN_Logger::log_char('"');
2563 TTCN_Logger::log_char_escaped(value_range
.max_value
);
2564 TTCN_Logger::log_char('"');
2565 } else TTCN_Logger::log_event("char(0, 0, 0, %u)",
2566 (unsigned char)value_range
.max_value
);
2567 } else TTCN_Logger::log_event_str("<unknown upper bound>");
2568 TTCN_Logger::log_char(')');
2577 void CHARSTRING_template::log_match(const CHARSTRING
& match_value
,
2578 boolean
/* legacy */) const
2580 if (TTCN_Logger::VERBOSITY_COMPACT
== TTCN_Logger::get_matching_verbosity()
2581 && TTCN_Logger::get_logmatch_buffer_len() != 0) {
2582 TTCN_Logger::print_logmatch_buffer();
2583 TTCN_Logger::log_event_str(" := ");
2586 TTCN_Logger::log_event_str(" with ");
2588 if (match(match_value
)) TTCN_Logger::log_event_str(" matched");
2589 else TTCN_Logger::log_event_str(" unmatched");
2592 void CHARSTRING_template::set_param(Module_Param
& param
) {
2593 param
.basic_check(Module_Param::BC_TEMPLATE
|Module_Param::BC_LIST
, "charstring template");
2594 Module_Param_Ptr mp
= ¶m
;
2595 if (param
.get_type() == Module_Param::MP_Reference
) {
2596 mp
= param
.get_referenced_param();
2598 switch (mp
->get_type()) {
2599 case Module_Param::MP_Omit
:
2602 case Module_Param::MP_Any
:
2605 case Module_Param::MP_AnyOrNone
:
2606 *this = ANY_OR_OMIT
;
2608 case Module_Param::MP_List_Template
:
2609 case Module_Param::MP_ComplementList_Template
: {
2610 CHARSTRING_template temp
;
2611 temp
.set_type(mp
->get_type() == Module_Param::MP_List_Template
?
2612 VALUE_LIST
: COMPLEMENTED_LIST
, mp
->get_size());
2613 for (size_t i
=0; i
<mp
->get_size(); i
++) {
2614 temp
.list_item(i
).set_param(*mp
->get_elem(i
));
2618 case Module_Param::MP_Charstring
:
2619 *this = CHARSTRING(mp
->get_string_size(), (char*)mp
->get_string_data());
2621 case Module_Param::MP_StringRange
: {
2622 universal_char lower_uchar
= mp
->get_lower_uchar();
2623 universal_char upper_uchar
= mp
->get_upper_uchar();
2624 if (!lower_uchar
.is_char()) param
.error("Lower bound of char range cannot be a multiple-byte character");
2625 if (!upper_uchar
.is_char()) param
.error("Upper bound of char range cannot be a multiple-byte character");
2627 set_selection(VALUE_RANGE
);
2628 value_range
.min_is_set
= TRUE
;
2629 value_range
.max_is_set
= TRUE
;
2630 value_range
.min_value
= (char)(lower_uchar
.uc_cell
);
2631 value_range
.max_value
= (char)(upper_uchar
.uc_cell
);
2633 case Module_Param::MP_Pattern
:
2635 single_value
= CHARSTRING(mp
->get_pattern());
2636 pattern_value
.regexp_init
= FALSE
;
2637 set_selection(STRING_PATTERN
);
2639 case Module_Param::MP_Expression
:
2640 if (mp
->get_expr_type() == Module_Param::EXPR_CONCATENATE
) {
2641 // only allow string patterns for the first operand
2642 CHARSTRING operand1
, operand2
, result
;
2643 boolean is_pattern
= operand1
.set_param_internal(*mp
->get_operand1(), TRUE
);
2644 operand2
.set_param(*mp
->get_operand2());
2645 result
= operand1
+ operand2
;
2648 single_value
= result
;
2649 pattern_value
.regexp_init
= FALSE
;
2650 set_selection(STRING_PATTERN
);
2657 param
.expr_type_error("a charstring");
2661 param
.type_error("charstring template");
2663 is_ifpresent
= param
.get_ifpresent() || mp
->get_ifpresent();
2664 if (param
.get_length_restriction() != NULL
) {
2665 set_length_range(param
);
2668 set_length_range(*mp
);
2672 Module_Param
* CHARSTRING_template::get_param(Module_Param_Name
& param_name
) const
2674 Module_Param
* mp
= NULL
;
2675 switch (template_selection
) {
2676 case UNINITIALIZED_TEMPLATE
:
2677 mp
= new Module_Param_Unbound();
2680 mp
= new Module_Param_Omit();
2683 mp
= new Module_Param_Any();
2686 mp
= new Module_Param_AnyOrNone();
2688 case SPECIFIC_VALUE
:
2689 mp
= single_value
.get_param(param_name
);
2692 case COMPLEMENTED_LIST
: {
2693 if (template_selection
== VALUE_LIST
) {
2694 mp
= new Module_Param_List_Template();
2697 mp
= new Module_Param_ComplementList_Template();
2699 for (size_t i
= 0; i
< value_list
.n_values
; ++i
) {
2700 mp
->add_elem(value_list
.list_value
[i
].get_param(param_name
));
2704 universal_char lower_bound
= { 0, 0, 0, (unsigned char)value_range
.min_value
};
2705 universal_char upper_bound
= { 0, 0, 0, (unsigned char)value_range
.max_value
};
2706 mp
= new Module_Param_StringRange(lower_bound
, upper_bound
);
2708 case STRING_PATTERN
:
2709 mp
= new Module_Param_Pattern(mcopystr(single_value
));
2715 mp
->set_ifpresent();
2717 mp
->set_length_restriction(get_length_range());
2721 void CHARSTRING_template::encode_text(Text_Buf
& text_buf
) const
2723 encode_text_restricted(text_buf
);
2724 switch (template_selection
) {
2729 case SPECIFIC_VALUE
:
2730 case STRING_PATTERN
:
2731 single_value
.encode_text(text_buf
);
2734 case COMPLEMENTED_LIST
:
2735 text_buf
.push_int(value_list
.n_values
);
2736 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2737 value_list
.list_value
[i
].encode_text(text_buf
);
2740 if (!value_range
.min_is_set
) TTCN_error("Text encoder: The lower bound is "
2741 "not set in a charstring value range template.");
2742 if (!value_range
.max_is_set
) TTCN_error("Text encoder: The upper bound is "
2743 "not set in a charstring value range template.");
2744 text_buf
.push_raw(1, &value_range
.min_value
);
2745 text_buf
.push_raw(1, &value_range
.max_value
);
2748 TTCN_error("Text encoder: Encoding an uninitialized/unsupported "
2749 "charstring template.");
2753 void CHARSTRING_template::decode_text(Text_Buf
& text_buf
)
2756 decode_text_restricted(text_buf
);
2757 switch (template_selection
) {
2762 case STRING_PATTERN
:
2763 pattern_value
.regexp_init
=FALSE
;
2765 case SPECIFIC_VALUE
:
2766 single_value
.decode_text(text_buf
);
2769 case COMPLEMENTED_LIST
:
2770 value_list
.n_values
= text_buf
.pull_int().get_val();
2771 value_list
.list_value
= new CHARSTRING_template
[value_list
.n_values
];
2772 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2773 value_list
.list_value
[i
].decode_text(text_buf
);
2776 text_buf
.pull_raw(1, &value_range
.min_value
);
2777 text_buf
.pull_raw(1, &value_range
.max_value
);
2778 if (value_range
.min_value
> value_range
.max_value
)
2779 TTCN_error("Text decoder: The received lower bound is greater than the "
2780 "upper bound in a charstring value range template.");
2781 value_range
.min_is_set
= TRUE
;
2782 value_range
.max_is_set
= TRUE
;
2785 TTCN_error("Text decoder: An unknown/unsupported selection was "
2786 "received for a charstring template.");
2790 boolean
CHARSTRING_template::is_present(boolean legacy
/* = FALSE */) const
2792 if (template_selection
==UNINITIALIZED_TEMPLATE
) return FALSE
;
2793 return !match_omit(legacy
);
2796 boolean
CHARSTRING_template::match_omit(boolean legacy
/* = FALSE */) const
2798 if (is_ifpresent
) return TRUE
;
2799 switch (template_selection
) {
2804 case COMPLEMENTED_LIST
:
2806 // legacy behavior: 'omit' can appear in the value/complement list
2807 for (unsigned int i
=0; i
<value_list
.n_values
; i
++)
2808 if (value_list
.list_value
[i
].match_omit())
2809 return template_selection
==VALUE_LIST
;
2810 return template_selection
==COMPLEMENTED_LIST
;
2812 // else fall through
2819 #ifndef TITAN_RUNTIME_2
2820 void CHARSTRING_template::check_restriction(template_res t_res
, const char* t_name
,
2821 boolean legacy
/* = FALSE */) const
2823 if (template_selection
==UNINITIALIZED_TEMPLATE
) return;
2824 switch ((t_name
&&(t_res
==TR_VALUE
))?TR_OMIT
:t_res
) {
2826 if (!is_ifpresent
&& template_selection
==SPECIFIC_VALUE
) return;
2829 if (!is_ifpresent
&& (template_selection
==OMIT_VALUE
||
2830 template_selection
==SPECIFIC_VALUE
)) return;
2833 if (!match_omit(legacy
)) return;
2838 TTCN_error("Restriction `%s' on template of type %s violated.",
2839 get_res_name(t_res
), t_name
? t_name
: "charstring");
2843 const CHARSTRING
& CHARSTRING_template::get_single_value() const {
2844 switch (template_selection
) {
2845 case STRING_PATTERN
:
2846 case SPECIFIC_VALUE
:
2849 TTCN_error("This template does not have single value.");
2851 return single_value
;