1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 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 boolean
CHARSTRING::set_param_internal(Module_Param
& param
, boolean allow_pattern
) {
630 boolean is_pattern
= FALSE
;
631 param
.basic_check(Module_Param::BC_VALUE
|Module_Param::BC_LIST
, "charstring value");
632 Module_Param_Ptr mp
= ¶m
;
633 if (param
.get_type() == Module_Param::MP_Reference
) {
634 mp
= param
.get_referenced_param();
636 switch (mp
->get_type()) {
637 case Module_Param::MP_Universal_Charstring
:
638 case Module_Param::MP_Charstring
:
639 switch (param
.get_operation_type()) {
640 case Module_Param::OT_ASSIGN
:
643 case Module_Param::OT_CONCAT
: {
644 // The universal charstring will decode the string value if it is UTF-8 encoded
645 UNIVERSAL_CHARSTRING ucs
;
647 if (ucs
.charstring
) {
648 // No special characters were found
650 *this = *this + ucs
.cstr
;
655 // Special characters found -> check if the UTF-8 decoding resulted in any multi-byte characters
656 for (int i
= 0; i
< ucs
.val_ptr
->n_uchars
; ++i
) {
657 if (0 != ucs
.val_ptr
->uchars_ptr
[i
].uc_group
||
658 0 != ucs
.val_ptr
->uchars_ptr
[i
].uc_plane
||
659 0 != ucs
.val_ptr
->uchars_ptr
[i
].uc_row
) {
660 param
.error("Type mismatch: a charstring value without multi-octet characters was expected.");
663 CHARSTRING
new_cs(ucs
.val_ptr
->n_uchars
);
664 for (int i
= 0; i
< ucs
.val_ptr
->n_uchars
; ++i
) {
665 new_cs
.val_ptr
->chars_ptr
[i
] = ucs
.val_ptr
->uchars_ptr
[i
].uc_cell
;
668 *this = *this + new_cs
;
675 TTCN_error("Internal error: CHARSTRING::set_param()");
678 case Module_Param::MP_Expression
:
679 if (mp
->get_expr_type() == Module_Param::EXPR_CONCATENATE
) {
680 // only allow string patterns for the first operand
681 CHARSTRING operand1
, operand2
;
682 is_pattern
= operand1
.set_param_internal(*mp
->get_operand1(), allow_pattern
);
683 operand2
.set_param(*mp
->get_operand2());
684 if (param
.get_operation_type() == Module_Param::OT_CONCAT
) {
685 *this = *this + operand1
+ operand2
;
688 *this = operand1
+ operand2
;
692 param
.expr_type_error("a charstring");
695 case Module_Param::MP_Pattern
:
697 *this = CHARSTRING(mp
->get_pattern());
703 param
.type_error("charstring value");
709 void CHARSTRING::set_param(Module_Param
& param
) {
710 set_param_internal(param
, FALSE
);
713 Module_Param
* CHARSTRING::get_param(Module_Param_Name
& /* param_name */) const
716 return new Module_Param_Unbound();
718 return new Module_Param_Charstring(val_ptr
->n_chars
, mcopystr(val_ptr
->chars_ptr
));
721 void CHARSTRING::encode_text(Text_Buf
& text_buf
) const
723 must_bound("Text encoder: Encoding an unbound charstring value.");
724 int n_chars
= val_ptr
->n_chars
;
725 text_buf
.push_int(n_chars
);
726 if (n_chars
> 0) text_buf
.push_raw(n_chars
, val_ptr
->chars_ptr
);
729 void CHARSTRING::decode_text(Text_Buf
& text_buf
)
731 int n_chars
= text_buf
.pull_int().get_val();
733 TTCN_error("Text decoder: invalid length of a charstring.");
735 init_struct(n_chars
);
736 if (n_chars
> 0) text_buf
.pull_raw(n_chars
, val_ptr
->chars_ptr
);
739 void CHARSTRING::encode(const TTCN_Typedescriptor_t
& p_td
,
741 TTCN_EncDec::coding_t p_coding
, ...) const
744 va_start(pvar
, p_coding
);
746 case TTCN_EncDec::CT_BER
: {
747 TTCN_EncDec_ErrorContext
ec("While BER-encoding type '%s': ", p_td
.name
);
748 unsigned BER_coding
=va_arg(pvar
, unsigned);
749 BER_encode_chk_coding(BER_coding
);
750 ASN_BER_TLV_t
*tlv
=BER_encode_TLV(p_td
, BER_coding
);
751 tlv
->put_in_buffer(p_buf
);
752 ASN_BER_TLV_t::destruct(tlv
);
754 case TTCN_EncDec::CT_RAW
: {
755 TTCN_EncDec_ErrorContext
ec("While RAW-encoding type '%s': ", p_td
.name
);
757 TTCN_EncDec_ErrorContext::error_internal
758 ("No RAW descriptor available for type '%s'.", p_td
.name
);
762 RAW_enc_tree
root(TRUE
,NULL
,&rp
,1,p_td
.raw
);
763 RAW_encode(p_td
, root
);
764 root
.put_to_buf(p_buf
);
766 case TTCN_EncDec::CT_TEXT
: {
767 TTCN_EncDec_ErrorContext
ec("While TEXT-encoding type '%s': ", p_td
.name
);
769 TTCN_EncDec_ErrorContext::error_internal
770 ("No TEXT descriptor available for type '%s'.", p_td
.name
);
771 TEXT_encode(p_td
,p_buf
);
773 case TTCN_EncDec::CT_XER
: {
774 TTCN_EncDec_ErrorContext
ec("While XER-encoding type '%s': ", p_td
.name
);
775 unsigned XER_coding
=va_arg(pvar
, unsigned);
776 XER_encode(*p_td
.xer
, p_buf
, XER_coding
, 0, 0);
779 case TTCN_EncDec::CT_JSON
: {
780 TTCN_EncDec_ErrorContext
ec("While JSON-encoding type '%s': ", p_td
.name
);
782 TTCN_EncDec_ErrorContext::error_internal
783 ("No JSON descriptor available for type '%s'.", p_td
.name
);
784 JSON_Tokenizer
tok(va_arg(pvar
, int) != 0);
785 JSON_encode(p_td
, tok
);
786 p_buf
.put_s(tok
.get_buffer_length(), (const unsigned char*)tok
.get_buffer());
789 TTCN_error("Unknown coding method requested to encode type '%s'",
795 void CHARSTRING::decode(const TTCN_Typedescriptor_t
& p_td
,
797 TTCN_EncDec::coding_t p_coding
, ...)
800 va_start(pvar
, p_coding
);
802 case TTCN_EncDec::CT_BER
: {
803 TTCN_EncDec_ErrorContext
ec("While BER-decoding type '%s': ", p_td
.name
);
804 unsigned L_form
=va_arg(pvar
, unsigned);
806 BER_decode_str2TLV(p_buf
, tlv
, L_form
);
807 BER_decode_TLV(p_td
, tlv
, L_form
);
808 if(tlv
.isComplete
) p_buf
.increase_pos(tlv
.get_len());
810 case TTCN_EncDec::CT_RAW
: {
811 TTCN_EncDec_ErrorContext
ec("While RAW-decoding type '%s': ", p_td
.name
);
813 TTCN_EncDec_ErrorContext::error_internal
814 ("No RAW descriptor available for type '%s'.", p_td
.name
);
816 switch(p_td
.raw
->top_bit_order
){
824 if(RAW_decode(p_td
, p_buf
, p_buf
.get_len()*8, order
)<0)
825 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
826 "Can not decode type '%s', because invalid or incomplete"
827 " message was received"
830 case TTCN_EncDec::CT_TEXT
: {
831 Limit_Token_List limit
;
832 TTCN_EncDec_ErrorContext
ec("While TEXT-decoding type '%s': ", p_td
.name
);
834 TTCN_EncDec_ErrorContext::error_internal
835 ("No TEXT descriptor available for type '%s'.", p_td
.name
);
836 const unsigned char *b
=p_buf
.get_data();
837 if(b
[p_buf
.get_len()-1]!='\0'){
838 p_buf
.set_pos(p_buf
.get_len());
839 p_buf
.put_zero(8,ORDER_LSB
);
842 if(TEXT_decode(p_td
,p_buf
,limit
)<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_XER
: {
849 TTCN_EncDec_ErrorContext
ec("While XER-decoding type '%s': ", p_td
.name
);
850 unsigned XER_coding
=va_arg(pvar
, unsigned);
851 XmlReaderWrap
reader(p_buf
);
852 int success
= reader
.Read();
853 for (; success
==1; success
=reader
.Read()) {
854 int type
= reader
.NodeType();
855 if (type
==XML_READER_TYPE_ELEMENT
)
858 XER_decode(*p_td
.xer
, reader
, XER_coding
, XER_NONE
, 0);
859 size_t bytes
= reader
.ByteConsumed();
860 p_buf
.set_pos(bytes
);
862 case TTCN_EncDec::CT_JSON
: {
863 TTCN_EncDec_ErrorContext
ec("While JSON-decoding type '%s': ", p_td
.name
);
865 TTCN_EncDec_ErrorContext::error_internal
866 ("No JSON descriptor available for type '%s'.", p_td
.name
);
867 JSON_Tokenizer
tok((const char*)p_buf
.get_data(), p_buf
.get_len());
868 if(JSON_decode(p_td
, tok
, false)<0)
869 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
870 "Can not decode type '%s', because invalid or incomplete"
871 " message was received"
873 p_buf
.set_pos(tok
.get_buf_pos());
876 TTCN_error("Unknown coding method requested to decode type '%s'",
883 CHARSTRING::BER_encode_TLV(const TTCN_Typedescriptor_t
& p_td
,
884 unsigned p_coding
) const
887 ASN_BER_TLV_t
*new_tlv
=BER_encode_chk_bound(is_bound());
889 new_tlv
=BER_encode_TLV_OCTETSTRING
890 (p_coding
, val_ptr
->n_chars
,
891 (const unsigned char*)val_ptr
->chars_ptr
);
893 new_tlv
=ASN_BER_V2TLV(new_tlv
, p_td
, p_coding
);
897 boolean
CHARSTRING::BER_decode_TLV(const TTCN_Typedescriptor_t
& p_td
,
898 const ASN_BER_TLV_t
& p_tlv
,
903 ASN_BER_TLV_t stripped_tlv
;
904 BER_decode_strip_tags(*p_td
.ber
, p_tlv
, L_form
, stripped_tlv
);
905 TTCN_EncDec_ErrorContext
ec("While decoding CHARSTRING type: ");
906 /* Upper estimation for the length. */
907 size_t stripped_tlv_len
= stripped_tlv
.get_len();
908 if (stripped_tlv_len
< 2) return FALSE
;
909 int max_len
= stripped_tlv_len
- 2;
910 init_struct(max_len
);
911 unsigned int octetnum_start
= 0;
912 BER_decode_TLV_OCTETSTRING(stripped_tlv
, L_form
, octetnum_start
,
914 (unsigned char*)val_ptr
->chars_ptr
);
915 if (val_ptr
->n_chars
< max_len
) {
916 if (val_ptr
->n_chars
== 0) {
920 val_ptr
= (charstring_struct
*)
921 Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
));
922 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
928 int CHARSTRING::TEXT_decode(const TTCN_Typedescriptor_t
& p_td
,
929 TTCN_Buffer
& buff
, Limit_Token_List
& limit
, boolean no_err
, boolean
/*first_call*/)
931 int decoded_length
= 0;
934 if (p_td
.text
->begin_decode
) {
936 if ((tl
= p_td
.text
->begin_decode
->match_begin(buff
)) < 0) {
937 if (no_err
) return -1;
938 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR
,
939 "The specified token '%s' not found for '%s': ",
940 (const char*) *(p_td
.text
->begin_decode
), p_td
.name
);
943 decoded_length
+= tl
;
944 buff
.increase_pos(tl
);
946 // never return "not enough bits"
947 // if(buff.get_read_len()<=1 && no_err) return -TTCN_EncDec::ET_LEN_ERR;
949 if (p_td
.text
->select_token
) {
951 if ((tl
= p_td
.text
->select_token
->match_begin(buff
)) < 0) {
952 if (no_err
) return -1;
957 else if ( p_td
.text
->val
.parameters
958 && p_td
.text
->val
.parameters
->decoding_params
.min_length
!= -1) {
959 str_len
= p_td
.text
->val
.parameters
->decoding_params
.min_length
;
961 else if (p_td
.text
->end_decode
) {
963 if ((tl
= p_td
.text
->end_decode
->match_first(buff
)) < 0) {
964 if (no_err
) return -1;
969 else if (limit
.has_token()) {
971 if ((tl
= limit
.match(buff
)) < 0) tl
= buff
.get_read_len() - 1;
975 str_len
= buff
.get_read_len() - 1;
978 init_struct(str_len
);
979 memcpy(val_ptr
->chars_ptr
, buff
.get_read_data(), str_len
);
980 decoded_length
+= str_len
;
981 buff
.increase_pos(str_len
);
983 if ( p_td
.text
->val
.parameters
984 && p_td
.text
->val
.parameters
->decoding_params
.convert
!= 0) {
985 if (p_td
.text
->val
.parameters
->decoding_params
.convert
== 1) {
986 for (int a
= 0; a
< str_len
; a
++) {
987 val_ptr
->chars_ptr
[a
] = toupper(val_ptr
->chars_ptr
[a
]);
991 for (int a
= 0; a
< str_len
; a
++) {
992 val_ptr
->chars_ptr
[a
] = tolower(val_ptr
->chars_ptr
[a
]);
996 if (p_td
.text
->end_decode
) {
998 if ((tl
= p_td
.text
->end_decode
->match_begin(buff
)) < 0) {
999 if (no_err
) return -1;
1000 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_TOKEN_ERR
,
1001 "The specified token '%s' not found for '%s': ",
1002 (const char*) *(p_td
.text
->end_decode
), p_td
.name
);
1005 decoded_length
+= tl
;
1006 buff
.increase_pos(tl
);
1008 return decoded_length
;
1011 int CHARSTRING::TEXT_encode(const TTCN_Typedescriptor_t
& p_td
,
1012 TTCN_Buffer
& buff
) const{
1013 int encoded_length
=0;
1014 if(p_td
.text
->begin_encode
){
1015 buff
.put_cs(*p_td
.text
->begin_encode
);
1016 encoded_length
+=p_td
.text
->begin_encode
->lengthof();
1019 TTCN_EncDec_ErrorContext::error
1020 (TTCN_EncDec::ET_UNBOUND
, "Encoding an unbound value.");
1021 if(p_td
.text
->end_encode
){
1022 buff
.put_cs(*p_td
.text
->end_encode
);
1023 encoded_length
+=p_td
.text
->end_encode
->lengthof();
1025 return encoded_length
;
1028 if(p_td
.text
->val
.parameters
==NULL
){
1030 encoded_length
+=val_ptr
->n_chars
;
1034 if(val_ptr
->n_chars
<p_td
.text
->val
.parameters
->coding_params
.min_length
){
1035 switch(p_td
.text
->val
.parameters
->coding_params
.just
){
1037 chars_after
=p_td
.text
->
1038 val
.parameters
->coding_params
.min_length
-val_ptr
->n_chars
;
1042 val
.parameters
->coding_params
.min_length
-val_ptr
->n_chars
;
1044 chars_before
=pad
-chars_after
;
1049 chars_before
=p_td
.text
->
1050 val
.parameters
->coding_params
.min_length
-val_ptr
->n_chars
;
1055 unsigned char* p
=NULL
;
1056 size_t len
=chars_before
;
1057 buff
.get_end(p
,len
);
1058 for(int a
=0;a
<chars_before
;a
++) p
[a
]=(unsigned char)' ';
1059 buff
.increase_length(chars_before
);
1060 encoded_length
+=chars_before
;
1063 switch(p_td
.text
->val
.parameters
->coding_params
.convert
){
1064 case -1:{ //lower_case
1065 unsigned char* p
=NULL
;
1066 size_t len
=val_ptr
->n_chars
;
1067 buff
.get_end(p
,len
);
1068 for(int a
=0;a
<val_ptr
->n_chars
;a
++)
1069 p
[a
]=(unsigned char)tolower(val_ptr
->chars_ptr
[a
]);
1070 buff
.increase_length(val_ptr
->n_chars
);
1073 case 0:{ // no conversion
1077 case 1: // upper_case
1080 unsigned char* p
=NULL
;
1081 size_t len
=val_ptr
->n_chars
;
1082 buff
.get_end(p
,len
);
1083 for(int a
=0;a
<val_ptr
->n_chars
;a
++)
1084 p
[a
]=(unsigned char)toupper(val_ptr
->chars_ptr
[a
]);
1085 buff
.increase_length(val_ptr
->n_chars
);
1089 encoded_length
+=val_ptr
->n_chars
;
1092 unsigned char* p
=NULL
;
1093 size_t len
=chars_after
;
1094 buff
.get_end(p
,len
);
1095 for(int a
=0;a
<chars_after
;a
++) p
[a
]=(unsigned char)' ';
1096 buff
.increase_length(chars_after
);
1097 encoded_length
+=chars_after
;
1102 if(p_td
.text
->end_encode
){
1103 buff
.put_cs(*p_td
.text
->end_encode
);
1104 encoded_length
+=p_td
.text
->end_encode
->lengthof();
1106 return encoded_length
;
1109 #ifdef TITAN_RUNTIME_2
1110 int CHARSTRING::encode_raw(TTCN_Buffer
& p_buf
) const
1112 p_buf
.put_string(*this);
1113 return val_ptr
? val_ptr
->n_chars
: 0;
1116 int CHARSTRING::JSON_encode_negtest_raw(JSON_Tokenizer
& p_tok
) const
1118 if (val_ptr
!= NULL
) {
1119 p_tok
.put_raw_data(val_ptr
->chars_ptr
, val_ptr
->n_chars
);
1120 return val_ptr
->n_chars
;
1127 void xml_escape(const unsigned int masked_c
, TTCN_Buffer
& p_buf
)
1130 // length of the majority of the names of control characters, +3 for </>
1131 static const char *escapes
[32] = {
1132 "<nul/>","<soh/>","<stx/>","<etx/>","<eot/>","<enq/>","<ack/>","<bel/>",
1133 "<bs/>" ,"<tab/>","<lf/>" ,"<vt/>" ,"<ff/>" ,"<cr/>" ,"<so/>" ,"<si/>" ,
1134 "<dle/>","<dc1/>","<dc2/>","<dc3/>","<dc4/>","<nak/>","<syn/>","<etb/>",
1135 "<can/>","<em/>" ,"<sub/>","<esc/>","<is4/>","<is3/>","<is2/>","<is1/>",
1137 unsigned int c
= (masked_c
& 0x7FFFFFFF); // unmasked
1140 // XML's "own" characters, escaped according to X.680/2002, 11.15.4 b)
1142 p_buf
.put_s(4, (cbyte
*)"<");
1146 p_buf
.put_s(4, (cbyte
*)">");
1150 p_buf
.put_s(5, (cbyte
*)"&");
1153 // Control characters, escaped according to X.680/2002, 11.15.5
1154 case 8: case 11: case 12: case 14: case 15: case 25:
1155 // the name of these control characters has only two letters
1158 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
1159 case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23:
1160 case 24: case 26: case 27: case 28: case 29: case 30: case 31:
1161 // 9=TAB 10=LF 13=CR are absent from this block altogether
1162 p_buf
.put_s(len
, (cbyte
*)escapes
[c
]);
1165 case '\"': // HR58225
1166 p_buf
.put_s(6, (cbyte
*)""");
1169 case '\'': // X.693 20.3.13: Titan uses single quotes for attributes;
1170 // so if they appear in content they must be escaped.
1171 // Currently this happens even if the string is not an attribute.
1172 p_buf
.put_s(6, (cbyte
*)"'");
1175 case 9: case 10: case 13:
1176 c
= masked_c
; // put the mask back on (makes it >127)
1179 if (c
> 127) { // XML numeric entity, as in X.680/2002 11.15.8
1180 c
&= 0x7FFFFFFF; // take it off again
1181 // Ensure that an even number of hex digits is produced
1182 int width
= (1 + (c
> 0xFF) + (c
> 0xFFFF) + (c
> 0xFFFFFF)) << 1;
1184 len
= snprintf(escapade
, 16, "&#x%0*X;", width
, c
);
1185 p_buf
.put_s(len
, (cbyte
*)(escapade
+0));
1187 else { // a plain old, unmolested character
1194 // Base64 encoder table
1195 extern const char cb64
[]=
1196 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1198 int CHARSTRING::XER_encode(const XERdescriptor_t
& p_td
,
1199 TTCN_Buffer
& p_buf
, unsigned int flavor
, int indent
, embed_values_enc_struct_t
*) const
1202 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
1203 "Encoding an unbound character string value.");
1205 int exer
= is_exer(flavor
|= SIMPLE_TYPE
);
1206 // SIMPLE_TYPE has no influence on is_exer, we set it for later
1207 int encoded_length
=(int)p_buf
.get_len();
1208 bool do_empty_element
= val_ptr
==NULL
|| val_ptr
->n_chars
== 0;
1210 flavor
&= ~XER_RECOF
; // charstring doesn't care
1212 if (do_empty_element
&& exer
&& p_td
.dfeValue
!= 0) {
1213 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_REPR
,
1214 "An encoded value with DEFAULT-FOR-EMPTY instruction applied should not be empty");
1216 if (begin_xml(p_td
, p_buf
, flavor
, indent
, do_empty_element
) == -1) {
1217 --encoded_length
; // it was shortened by one
1220 if (!do_empty_element
) {
1221 const char * current
= val_ptr
->chars_ptr
;
1222 const char * const end
= val_ptr
->chars_ptr
+ val_ptr
->n_chars
;
1223 const char * to_escape
;
1225 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
1226 to_escape
= "<&>'\"\x09\x0A\x0D";
1227 mask
= 0x80000000; // guaranteed bigger than any Unicode character
1230 to_escape
= "<&>'\"";
1234 // If Base64 is needed, use a temporary buffer.
1235 TTCN_Buffer tmpbuf
, &rbuf
= (exer
&& (p_td
.xer_bits
& BASE_64
)) ? tmpbuf
: p_buf
;
1237 // This here is an optimization. Only <&> need to be escaped.
1238 // Contiguous runs of "ordinary" characters are put in the buffer
1239 // with a single call.
1240 // TODO: is it really faster ? strpbrk is probably O(nm)
1241 while ( const char * trouble
= strpbrk(current
, to_escape
) ) {
1242 rbuf
.put_s((size_t)(trouble
- current
), (cbyte
*)current
);
1243 xml_escape(*trouble
| mask
, rbuf
); // escape the troublesome character
1244 current
= trouble
+1;
1247 // put the remainder in the buffer
1248 rbuf
.put_s( (size_t)(end
- current
), (cbyte
*)current
);
1250 if (exer
&& (p_td
.xer_bits
& BASE_64
)) {
1251 size_t clear_len
= tmpbuf
.get_len(); // the length before padding
1252 // Pad the temporary buffer so i+1 and i+2 don't go outside the buffer
1253 unsigned char zero
[2] = {0,0};
1254 tmpbuf
.put_s(2, zero
);
1255 // Get the buffer after the possible realloc caused by the padding.
1256 cbyte
* in
= tmpbuf
.get_data();
1258 // Encode 3 bytes of cleartext into 4 bytes of Base64
1259 for (size_t i
= 0; i
< clear_len
; i
+= 3) {
1260 p_buf
.put_c( cb64
[ in
[i
] >> 2 ] );
1261 p_buf
.put_c( cb64
[ ((in
[i
] & 0x03) << 4) | ((in
[i
+1] & 0xf0) >> 4) ]);
1262 p_buf
.put_c( i
+1 < clear_len
1263 ? cb64
[ ((in
[i
+1] & 0x0f) << 2) | ((in
[i
+2] & 0xc0) >> 6) ]
1265 p_buf
.put_c( i
+2 < clear_len
? cb64
[ in
[i
+2] & 0x3f ] : '=' );
1270 end_xml(p_td
, p_buf
, flavor
, indent
, do_empty_element
);
1271 return (int)p_buf
.get_len() - encoded_length
;
1275 * Translates a Base64 value to either its 6-bit reconstruction value
1276 * or a negative number indicating some other meaning.
1277 * Public domain from http://iharder.net/base64 */
1278 char base64_decoder_table
[256] =
1280 -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
1281 -5,-5, // Whitespace: Tab and Linefeed
1282 -9,-9, // Decimal 11 - 12
1283 -5, // Whitespace: Carriage Return
1284 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
1285 -9,-9,-9,-9,-9, // Decimal 27 - 31
1286 -5, // Whitespace: Space
1287 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
1288 62, // Plus sign at decimal 43
1289 -9,-9,-9, // Decimal 44 - 46
1290 63, // Slash at decimal 47
1291 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
1292 -9,-9,-9, // Decimal 58 - 60
1293 -1, // Equals sign at decimal 61
1294 -9,-9,-9, // Decimal 62 - 64
1295 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
1296 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
1297 -9,-9,-9,-9,-9,-9, // Decimal 91 - 96
1298 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
1299 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
1300 -9,-9,-9,-9,-9 // Decimal 123 - 127
1301 ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
1302 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
1303 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
1304 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
1305 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
1306 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
1307 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
1308 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
1309 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
1310 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
1313 unsigned int xlate(cbyte
*in
, int phase
, unsigned char*dest
) {
1314 static unsigned char nbytes
[4] = { 3,1,1,2 };
1315 unsigned char out
[4];
1316 out
[0] = in
[0] << 2 | in
[1] >> 4;
1317 out
[1] = in
[1] << 4 | in
[2] >> 2;
1318 out
[2] = in
[2] << 6 | in
[3] >> 0;
1319 memcpy(dest
, out
, nbytes
[phase
]);
1320 return nbytes
[phase
];
1323 int CHARSTRING::XER_decode(const XERdescriptor_t
& p_td
, XmlReaderWrap
& reader
,
1324 unsigned int flavor
, unsigned int /*flavor2*/, embed_values_dec_struct_t
*) {
1325 int exer
= is_exer(flavor
);
1326 int success
= reader
.Ok(), depth
= -1;
1328 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
1329 const char * name
= verify_name(reader
, p_td
, exer
);
1331 const char * value
= (const char *)reader
.Value();
1332 // FIXME copy & paste
1335 // Let the caller do reader.AdvanceAttribute();
1338 bool omit_tag
= exer
1339 && (p_td
.xer_bits
& UNTAGGED
|| flavor
& (EMBED_VALUES
|XER_LIST
|USE_TYPE_ATTR
|USE_NIL
));
1340 for (; success
== 1; success
= reader
.Read()) {
1341 int type
= reader
.NodeType();
1342 if (XML_READER_TYPE_ELEMENT
== type
) {
1343 verify_name(reader
, p_td
, exer
);
1344 if (reader
.IsEmptyElement()) { // has no text, needs special processing
1345 if (exer
&& p_td
.dfeValue
!= 0) {
1346 *this = *static_cast<const CHARSTRING
*>(p_td
.dfeValue
);
1348 else init_struct(0);
1350 break; // exit the loop early
1351 } // if empty element
1352 // otherwise, not an empty element, stay in the loop
1353 depth
= reader
.Depth();
1355 else if ((depth
!= -1 || omit_tag
)
1356 && (XML_READER_TYPE_TEXT
== type
|| XML_READER_TYPE_CDATA
== type
))
1357 // Process #text node if we already processed the element node, or
1358 // there is no element node because UNTAGGED is in effect.
1360 const xmlChar
* value
= reader
.Value();
1361 size_t num_chars
= strlen((const char*)value
);
1363 if (exer
&& (p_td
.xer_bits
& BASE_64
)) {
1365 init_struct(num_chars
* 3 / 4);
1369 unsigned char * dest
= (unsigned char *)val_ptr
->chars_ptr
;
1371 for (size_t o
=0; o
<num_chars
; ++o
) {
1372 xmlChar c
= value
[o
];
1373 if(c
== '=') { // Padding starts; decode last chunk and exit.
1374 dest
+= xlate(in
,phase
, dest
);
1378 int val
= base64_decoder_table
[c
];
1381 phase
= (phase
+ 1) % 4;
1383 dest
+= xlate(in
,phase
, dest
);
1384 in
[0]=in
[1]=in
[2]=in
[3]=0;
1387 else if (exer
&& (flavor
& EXIT_ON_ERROR
)) {
1391 TTCN_EncDec_ErrorContext::warning(
1392 /* if this was an error... TTCN_EncDec::ET_INVAL_MSG,*/
1393 "Invalid character for Base64 '%02X'", c
);
1397 val_ptr
->n_chars
= (char*)dest
- val_ptr
->chars_ptr
;
1401 init_struct(num_chars
);
1402 memcpy(val_ptr
->chars_ptr
, value
, num_chars
);
1406 // find the end element
1407 for (success
= reader
.Read(); success
== 1; success
= reader
.Read()) {
1408 type
= reader
.NodeType();
1409 if (XML_READER_TYPE_END_ELEMENT
== type
) {
1410 verify_end(reader
, p_td
, depth
, exer
);
1411 reader
.Read(); // one last time
1418 else if (XML_READER_TYPE_END_ELEMENT
== type
) {
1420 verify_end(reader
, p_td
, depth
, exer
);
1422 // We are at our end tag and no content
1423 if (exer
&& p_td
.dfeValue
!= 0) {
1424 *this = *static_cast<const CHARSTRING
*>(p_td
.dfeValue
);
1426 else init_struct(0); // empty string
1435 if (exer
&& p_td
.whitespace
>= WHITESPACE_REPLACE
) { // includes _COLLAPSE
1436 for (int i
=0; i
<val_ptr
->n_chars
; ++i
) { // first, _REPLACE
1437 switch (val_ptr
->chars_ptr
[i
]) {
1438 case 9: // HORIZONTAL TAB
1439 case 10: // LINE FEED
1440 case 13: // CARRIAGE RETURN
1441 val_ptr
->chars_ptr
[i
] = ' ';
1448 if (p_td
.whitespace
>= WHITESPACE_COLLAPSE
) {
1450 const char *from
, *end
= val_ptr
->chars_ptr
+ val_ptr
->n_chars
;
1451 for (from
= to
= val_ptr
->chars_ptr
; from
< end
;) {
1453 // If the copied character (*to) was a space,
1454 // and the next character to be copied (*from) is also a space
1455 // (continuous run of spaces)
1456 // or this was the first character (leading spaces to be trimmed),
1457 // then don't advance the destination (will be overwritten).
1459 || (from
< end
&& *from
!= ' ' && to
> val_ptr
->chars_ptr
)) ++to
;
1462 val_ptr
->n_chars
= to
- val_ptr
->chars_ptr
; // truncate
1463 // TODO maybe realloc after truncation
1470 int CHARSTRING::RAW_encode(const TTCN_Typedescriptor_t
& p_td
,
1471 RAW_enc_tree
& myleaf
) const
1473 int bl
= val_ptr
->n_chars
* 8; // bit length
1474 int align_length
= p_td
.raw
->fieldlength
? p_td
.raw
->fieldlength
- bl
: 0;
1476 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
1477 "Encoding an unbound value.");
1479 if ((bl
+ align_length
) < val_ptr
->n_chars
* 8) {
1480 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
1481 "There is no sufficient bits to encode '%s': ", p_td
.name
);
1482 bl
= p_td
.raw
->fieldlength
;
1485 if (myleaf
.must_free
) Free(myleaf
.body
.leaf
.data_ptr
);
1486 myleaf
.must_free
= FALSE
;
1487 myleaf
.data_ptr_used
= TRUE
;
1488 myleaf
.body
.leaf
.data_ptr
= (unsigned char*) val_ptr
->chars_ptr
;
1489 if (p_td
.raw
->endianness
== ORDER_MSB
) myleaf
.align
= -align_length
;
1490 else myleaf
.align
= align_length
;
1491 return myleaf
.length
= bl
+ align_length
;
1494 int CHARSTRING::RAW_decode(const TTCN_Typedescriptor_t
& p_td
,
1495 TTCN_Buffer
& buff
, int limit
, raw_order_t top_bit_ord
, boolean no_err
,
1496 int /*sel_field*/, boolean
/*first_call*/)
1498 int prepaddlength
= buff
.increase_pos_padd(p_td
.raw
->prepadding
);
1499 limit
-= prepaddlength
;
1500 int decode_length
= p_td
.raw
->fieldlength
== 0
1501 ? (limit
/ 8) * 8 : p_td
.raw
->fieldlength
;
1502 if ( decode_length
> limit
1503 || decode_length
> (int) buff
.unread_len_bit()) {
1504 if (no_err
) return -TTCN_EncDec::ET_LEN_ERR
;
1505 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
1506 "There is not enough bits in the buffer to decode type %s.", p_td
.name
);
1507 decode_length
= ((limit
> (int) buff
.unread_len_bit() ? (int)buff
.unread_len_bit() : limit
) / 8) * 8;
1510 boolean orders
= FALSE
;
1511 if (p_td
.raw
->bitorderinoctet
== ORDER_MSB
) orders
= TRUE
;
1512 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
1513 cp
.bitorder
= orders
? ORDER_MSB
: ORDER_LSB
;
1515 if (p_td
.raw
->byteorder
== ORDER_MSB
) orders
= TRUE
;
1516 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
1517 cp
.byteorder
= orders
? ORDER_MSB
: ORDER_LSB
;
1518 cp
.fieldorder
= p_td
.raw
->fieldorder
;
1519 cp
.hexorder
= ORDER_LSB
;
1521 init_struct(decode_length
/ 8);
1522 buff
.get_b((size_t) decode_length
, (unsigned char*) val_ptr
->chars_ptr
, cp
,
1525 if (p_td
.raw
->length_restrition
!= -1) {
1526 val_ptr
->n_chars
= p_td
.raw
->length_restrition
;
1527 if (p_td
.raw
->endianness
== ORDER_MSB
) memmove(val_ptr
->chars_ptr
,
1528 val_ptr
->chars_ptr
+ (decode_length
/ 8 - val_ptr
->n_chars
),
1529 val_ptr
->n_chars
); // sizeof(char) == 1 by definition
1531 decode_length
+= buff
.increase_pos_padd(p_td
.raw
->padding
);
1532 return decode_length
+ prepaddlength
;
1535 char* CHARSTRING::to_JSON_string() const
1537 // Need at least 3 more characters (the double quotes around the string and the terminating zero)
1538 char* json_str
= (char*)Malloc(val_ptr
->n_chars
+ 3);
1541 json_str
= mputc(json_str
, '\"');
1543 for (int i
= 0; i
< val_ptr
->n_chars
; ++i
) {
1544 // Increase the size of the buffer if it's not big enough to store the
1545 // characters remaining in the charstring plus 1 (for safety, in case this
1546 // character needs to be double-escaped).
1547 switch(val_ptr
->chars_ptr
[i
]) {
1549 json_str
= mputstrn(json_str
, "\\\\", 2);
1552 json_str
= mputstrn(json_str
, "\\n", 2);
1555 json_str
= mputstrn(json_str
, "\\t", 2);
1558 json_str
= mputstrn(json_str
, "\\r", 2);
1561 json_str
= mputstrn(json_str
, "\\f", 2);
1564 json_str
= mputstrn(json_str
, "\\b", 2);
1567 json_str
= mputstrn(json_str
, "\\\"", 2);
1570 json_str
= mputc(json_str
, val_ptr
->chars_ptr
[i
]);
1575 json_str
= mputc(json_str
, '\"');
1579 boolean
CHARSTRING::from_JSON_string(const char* p_value
, size_t p_value_len
, boolean check_quotes
)
1582 size_t end
= p_value_len
;
1585 end
= p_value_len
- 1;
1586 if (p_value
[0] != '\"' || p_value
[p_value_len
- 1] != '\"') {
1591 // The charstring will be shorter than the JSON string, at least by the 2 quotes
1592 char* str
= (char*)Malloc(end
- start
);
1594 boolean error
= false;
1596 for (size_t i
= start
; i
< end
; ++i
) {
1597 if (0 > p_value
[i
]) {
1601 if ('\\' == p_value
[i
]) {
1606 switch(p_value
[i
+ 1]) {
1632 if (end
- i
>= 6 && '0' == p_value
[i
+ 2] && '0' == p_value
[i
+ 3]) {
1633 unsigned char upper_nibble
= char_to_hexdigit(p_value
[i
+ 4]);
1634 unsigned char lower_nibble
= char_to_hexdigit(p_value
[i
+ 5]);
1635 if (0x07 >= upper_nibble
&& 0x0F >= lower_nibble
) {
1636 str
[len
++] = (upper_nibble
<< 4) | lower_nibble
;
1637 // skip 4 extra characters (the 4 hex digits)
1640 // error (found something other than hex digits) -> leave the for cycle
1645 // error (not enough characters left or the first 2 hex digits are non-null) -> leave the for cycle
1652 // error (invalid escaped character) -> leave the for cycle
1657 // skip an extra character (the \)
1660 str
[len
++] = p_value
[i
];
1663 if (check_quotes
&& i
== p_value_len
- 1) {
1664 // Special case: the last 2 characters are double escaped quotes ('\\' and '\"')
1672 memcpy(val_ptr
->chars_ptr
, str
, len
);
1673 val_ptr
->chars_ptr
[len
] = 0;
1679 int CHARSTRING::JSON_encode(const TTCN_Typedescriptor_t
&, JSON_Tokenizer
& p_tok
) const
1682 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
1683 "Encoding an unbound charstring value.");
1687 char* tmp_str
= to_JSON_string();
1688 int enc_len
= p_tok
.put_next_token(JSON_TOKEN_STRING
, tmp_str
);
1693 int CHARSTRING::JSON_decode(const TTCN_Typedescriptor_t
& p_td
, JSON_Tokenizer
& p_tok
, boolean p_silent
)
1695 json_token_t token
= JSON_TOKEN_NONE
;
1697 size_t value_len
= 0;
1699 boolean use_default
= p_td
.json
->default_value
&& 0 == p_tok
.get_buffer_length();
1701 // No JSON data in the buffer -> use default value
1702 value
= (char*)p_td
.json
->default_value
;
1703 value_len
= strlen(value
);
1705 dec_len
= p_tok
.get_next_token(&token
, &value
, &value_len
);
1707 if (JSON_TOKEN_ERROR
== token
) {
1708 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_BAD_TOKEN_ERROR
, "");
1709 return JSON_ERROR_FATAL
;
1711 else if (JSON_TOKEN_STRING
== token
|| use_default
) {
1712 if (!from_JSON_string(value
, value_len
, !use_default
)) {
1713 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_FORMAT_ERROR
, "string", "charstring");
1715 return JSON_ERROR_FATAL
;
1718 return JSON_ERROR_INVALID_TOKEN
;
1724 CHARSTRING_ELEMENT::CHARSTRING_ELEMENT(boolean par_bound_flag
,
1725 CHARSTRING
& par_str_val
, int par_char_pos
)
1726 : bound_flag(par_bound_flag
), str_val(par_str_val
), char_pos(par_char_pos
)
1731 CHARSTRING_ELEMENT
& CHARSTRING_ELEMENT::operator=(const char* other_value
)
1733 if (other_value
== NULL
||
1734 other_value
[0] == '\0' || other_value
[1] != '\0')
1735 TTCN_error("Assignment of a charstring value with length other "
1736 "than 1 to a charstring element.");
1738 str_val
.copy_value();
1739 str_val
.val_ptr
->chars_ptr
[char_pos
] = other_value
[0];
1743 CHARSTRING_ELEMENT
& CHARSTRING_ELEMENT::operator=
1744 (const CHARSTRING
& other_value
)
1746 other_value
.must_bound("Assignment of an unbound charstring value to a "
1747 "charstring element.");
1748 if(other_value
.val_ptr
->n_chars
!= 1)
1749 TTCN_error("Assignment of a charstring value with length other than "
1750 "1 to a charstring element.");
1752 str_val
.copy_value();
1753 str_val
.val_ptr
->chars_ptr
[char_pos
] = other_value
.val_ptr
->chars_ptr
[0];
1757 CHARSTRING_ELEMENT
& CHARSTRING_ELEMENT::operator=
1758 (const CHARSTRING_ELEMENT
& other_value
)
1760 other_value
.must_bound("Assignment of an unbound charstring element.");
1761 if (&other_value
!= this) {
1763 str_val
.copy_value();
1764 str_val
.val_ptr
->chars_ptr
[char_pos
] =
1765 other_value
.str_val
.val_ptr
->chars_ptr
[other_value
.char_pos
];
1770 boolean
CHARSTRING_ELEMENT::operator==(const char *other_value
) const
1772 must_bound("Comparison of an unbound charstring element.");
1773 if (other_value
== NULL
|| other_value
[0] == '\0' ||
1774 other_value
[1] != '\0') return FALSE
;
1775 return str_val
.val_ptr
->chars_ptr
[char_pos
] == other_value
[0];
1778 boolean
CHARSTRING_ELEMENT::operator==(const CHARSTRING
& other_value
) const
1780 must_bound("Comparison of an unbound charstring element.");
1781 other_value
.must_bound("Comparison of an unbound charstring value.");
1782 if (other_value
.val_ptr
->n_chars
!= 1) return FALSE
;
1783 return str_val
.val_ptr
->chars_ptr
[char_pos
] ==
1784 other_value
.val_ptr
->chars_ptr
[0];
1787 boolean
CHARSTRING_ELEMENT::operator==(const CHARSTRING_ELEMENT
& other_value
) const
1789 must_bound("Comparison of an unbound charstring element.");
1790 other_value
.must_bound("Comparison of an unbound charstring element.");
1791 return str_val
.val_ptr
->chars_ptr
[char_pos
] ==
1792 other_value
.str_val
.val_ptr
->chars_ptr
[other_value
.char_pos
];
1795 boolean
CHARSTRING_ELEMENT::operator==(const UNIVERSAL_CHARSTRING
& other_value
)
1798 must_bound("The left operand of comparison is an unbound charstring "
1800 other_value
.must_bound("The right operand of comparison is an unbound "
1801 "universal charstring value.");
1802 if (other_value
.charstring
) {
1803 if (other_value
.cstr
.val_ptr
->n_chars
!= 1) return FALSE
;
1804 return str_val
.val_ptr
->chars_ptr
[char_pos
] ==
1805 other_value
.cstr
.val_ptr
->chars_ptr
[0];
1808 if (other_value
.val_ptr
->n_uchars
!= 1) return FALSE
;
1809 return other_value
.val_ptr
->uchars_ptr
[0].uc_group
== 0 &&
1810 other_value
.val_ptr
->uchars_ptr
[0].uc_plane
== 0 &&
1811 other_value
.val_ptr
->uchars_ptr
[0].uc_row
== 0 &&
1812 other_value
.val_ptr
->uchars_ptr
[0].uc_cell
==
1813 (cbyte
)str_val
.val_ptr
->chars_ptr
[char_pos
];
1817 boolean
CHARSTRING_ELEMENT::operator==
1818 (const UNIVERSAL_CHARSTRING_ELEMENT
& other_value
) const
1820 must_bound("The left operand of comparison is an unbound charstring "
1822 other_value
.must_bound("The right operand of comparison is an unbound "
1823 "universal charstring element.");
1824 const universal_char
& uchar
= other_value
.get_uchar();
1825 return uchar
.uc_group
== 0 && uchar
.uc_plane
== 0 && uchar
.uc_row
== 0 &&
1826 uchar
.uc_cell
== (cbyte
)str_val
.val_ptr
->chars_ptr
[char_pos
];
1829 CHARSTRING
CHARSTRING_ELEMENT::operator+(const char *other_value
) const
1831 must_bound("Unbound operand of charstring element concatenation.");
1833 if (other_value
== NULL
) other_len
= 0;
1834 else other_len
= strlen(other_value
);
1835 CHARSTRING
ret_val(other_len
+ 1);
1836 ret_val
.val_ptr
->chars_ptr
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1837 memcpy(ret_val
.val_ptr
->chars_ptr
+ 1, other_value
, other_len
);
1841 CHARSTRING
CHARSTRING_ELEMENT::operator+(const CHARSTRING
& other_value
) const
1843 must_bound("Unbound operand of charstring element concatenation.");
1844 other_value
.must_bound("Unbound operand of charstring concatenation.");
1845 int n_chars
= other_value
.val_ptr
->n_chars
;
1846 CHARSTRING
ret_val(n_chars
+ 1);
1847 ret_val
.val_ptr
->chars_ptr
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1848 memcpy(ret_val
.val_ptr
->chars_ptr
+ 1, other_value
.val_ptr
->chars_ptr
,
1853 CHARSTRING
CHARSTRING_ELEMENT::operator+(const CHARSTRING_ELEMENT
&
1856 must_bound("Unbound operand of charstring element concatenation.");
1857 other_value
.must_bound("Unbound operand of charstring element "
1860 result
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1861 result
[1] = other_value
.str_val
.val_ptr
->chars_ptr
[other_value
.char_pos
];
1862 return CHARSTRING(2, result
);
1865 UNIVERSAL_CHARSTRING
CHARSTRING_ELEMENT::operator+
1866 (const UNIVERSAL_CHARSTRING
& other_value
) const
1868 must_bound("The left operand of concatenation is an unbound charstring "
1870 other_value
.must_bound("The right operand of concatenation is an unbound "
1871 "universal charstring value.");
1872 if (other_value
.charstring
) {
1873 UNIVERSAL_CHARSTRING
ret_val(other_value
.cstr
.val_ptr
->n_chars
+ 1, true);
1874 ret_val
.cstr
.val_ptr
->chars_ptr
[0] = str_val
.val_ptr
->chars_ptr
[char_pos
];
1875 memcpy(ret_val
.cstr
.val_ptr
->chars_ptr
+ 1, other_value
.cstr
.val_ptr
->chars_ptr
, other_value
.cstr
.val_ptr
->n_chars
);
1878 UNIVERSAL_CHARSTRING
ret_val(other_value
.val_ptr
->n_uchars
+ 1);
1879 ret_val
.val_ptr
->uchars_ptr
[0].uc_group
= 0;
1880 ret_val
.val_ptr
->uchars_ptr
[0].uc_plane
= 0;
1881 ret_val
.val_ptr
->uchars_ptr
[0].uc_row
= 0;
1882 ret_val
.val_ptr
->uchars_ptr
[0].uc_cell
= str_val
.val_ptr
->chars_ptr
[char_pos
];
1883 memcpy(ret_val
.val_ptr
->uchars_ptr
+ 1, other_value
.val_ptr
->uchars_ptr
,
1884 other_value
.val_ptr
->n_uchars
* sizeof(universal_char
));
1889 UNIVERSAL_CHARSTRING
CHARSTRING_ELEMENT::operator+
1890 (const UNIVERSAL_CHARSTRING_ELEMENT
& other_value
) const
1892 must_bound("The left operand of concatenation is an unbound charstring "
1894 other_value
.must_bound("The right operand of concatenation is an unbound "
1895 "universal charstring element.");
1896 universal_char result
[2];
1897 result
[0].uc_group
= 0;
1898 result
[0].uc_plane
= 0;
1899 result
[0].uc_row
= 0;
1900 result
[0].uc_cell
= str_val
.val_ptr
->chars_ptr
[char_pos
];
1901 result
[1] = other_value
.get_uchar();
1902 return UNIVERSAL_CHARSTRING(2, result
);
1905 char CHARSTRING_ELEMENT::get_char() const
1907 return str_val
.val_ptr
->chars_ptr
[char_pos
];
1910 void CHARSTRING_ELEMENT::log() const
1913 char c
= str_val
.val_ptr
->chars_ptr
[char_pos
];
1914 if (TTCN_Logger::is_printable(c
)) {
1915 TTCN_Logger::log_char('"');
1916 TTCN_Logger::log_char_escaped(c
);
1917 TTCN_Logger::log_char('"');
1918 } else TTCN_Logger::log_event("char(0, 0, 0, %u)", (unsigned char)c
);
1919 } else TTCN_Logger::log_event_unbound();
1924 boolean
operator==(const char* string_value
, const CHARSTRING
& other_value
)
1926 other_value
.must_bound("Unbound operand of charstring comparison.");
1927 if (string_value
== NULL
) string_value
= "";
1928 return !strcmp(string_value
, other_value
.val_ptr
->chars_ptr
);
1931 boolean
operator==(const char* string_value
,
1932 const CHARSTRING_ELEMENT
& other_value
)
1934 other_value
.must_bound("Unbound operand of charstring element "
1936 if (string_value
== NULL
|| string_value
[0] == '\0' ||
1937 string_value
[1] != '\0') return FALSE
;
1938 return string_value
[0] == other_value
.get_char();
1941 CHARSTRING
operator+(const char* string_value
, const CHARSTRING
& other_value
)
1943 other_value
.must_bound("Unbound operand of charstring concatenation.");
1945 if (string_value
== NULL
) string_len
= 0;
1946 else string_len
= strlen(string_value
);
1947 if (string_len
== 0) return other_value
;
1948 CHARSTRING
ret_val(string_len
+ other_value
.val_ptr
->n_chars
);
1949 memcpy(ret_val
.val_ptr
->chars_ptr
, string_value
, string_len
);
1950 memcpy(ret_val
.val_ptr
->chars_ptr
+ string_len
,
1951 other_value
.val_ptr
->chars_ptr
, other_value
.val_ptr
->n_chars
);
1955 CHARSTRING
operator+(const char* string_value
,
1956 const CHARSTRING_ELEMENT
& other_value
)
1958 other_value
.must_bound("Unbound operand of charstring element "
1961 if (string_value
== NULL
) string_len
= 0;
1962 else string_len
= strlen(string_value
);
1963 if (string_len
== 0) return CHARSTRING(other_value
);
1964 CHARSTRING
ret_val(string_len
+ 1);
1965 memcpy(ret_val
.val_ptr
->chars_ptr
, string_value
, string_len
);
1966 ret_val
.val_ptr
->chars_ptr
[string_len
] = other_value
.get_char();
1970 CHARSTRING
operator<<=(const char *string_value
, const INTEGER
& rotate_count
)
1972 return CHARSTRING(string_value
) <<= rotate_count
;
1975 CHARSTRING
operator>>=(const char *string_value
, const INTEGER
& rotate_count
)
1977 return CHARSTRING(string_value
) >>= rotate_count
;
1980 // charstring template class
1982 void CHARSTRING_template::clean_up()
1984 switch(template_selection
) {
1986 case COMPLEMENTED_LIST
:
1987 delete [] value_list
.list_value
;
1989 case STRING_PATTERN
:
1990 if (pattern_value
.regexp_init
) regfree(&pattern_value
.posix_regexp
);
1995 template_selection
= UNINITIALIZED_TEMPLATE
;
1998 void CHARSTRING_template::copy_template(const CHARSTRING_template
& other_value
)
2000 switch (other_value
.template_selection
) {
2001 case STRING_PATTERN
:
2002 pattern_value
.regexp_init
= FALSE
;
2004 case SPECIFIC_VALUE
:
2005 single_value
= other_value
.single_value
;
2012 case COMPLEMENTED_LIST
:
2013 value_list
.n_values
= other_value
.value_list
.n_values
;
2014 value_list
.list_value
= new CHARSTRING_template
[value_list
.n_values
];
2015 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2016 value_list
.list_value
[i
].copy_template(
2017 other_value
.value_list
.list_value
[i
]);
2020 if (!other_value
.value_range
.min_is_set
) TTCN_error("The lower bound is "
2021 "not set when copying a charstring value range template.");
2022 if (!other_value
.value_range
.max_is_set
) TTCN_error("The upper bound is "
2023 "not set when copying a charstring value range template.");
2024 value_range
= other_value
.value_range
;
2027 TTCN_error("Copying an uninitialized/unsupported charstring template.");
2029 set_selection(other_value
);
2032 CHARSTRING_template::CHARSTRING_template()
2036 CHARSTRING_template::CHARSTRING_template(template_sel other_value
)
2037 : Restricted_Length_Template(other_value
)
2039 check_single_selection(other_value
);
2042 CHARSTRING_template::CHARSTRING_template(const CHARSTRING
& other_value
)
2043 : Restricted_Length_Template(SPECIFIC_VALUE
), single_value(other_value
)
2047 CHARSTRING_template::CHARSTRING_template(const CHARSTRING_ELEMENT
& other_value
)
2048 : Restricted_Length_Template(SPECIFIC_VALUE
), single_value(other_value
)
2052 CHARSTRING_template::CHARSTRING_template(const OPTIONAL
<CHARSTRING
>& other_value
)
2054 switch (other_value
.get_selection()) {
2055 case OPTIONAL_PRESENT
:
2056 set_selection(SPECIFIC_VALUE
);
2057 single_value
= (const CHARSTRING
&)other_value
;
2060 set_selection(OMIT_VALUE
);
2063 TTCN_error("Creating a charstring template from an unbound optional "
2068 CHARSTRING_template::CHARSTRING_template(template_sel p_sel
,
2069 const CHARSTRING
& p_str
)
2070 : Restricted_Length_Template(STRING_PATTERN
), single_value(p_str
)
2072 if(p_sel
!=STRING_PATTERN
)
2073 TTCN_error("Internal error: Initializing a charstring pattern template "
2074 "with invalid selection.");
2075 pattern_value
.regexp_init
=FALSE
;
2078 CHARSTRING_template::CHARSTRING_template(const CHARSTRING_template
& other_value
)
2079 : Restricted_Length_Template()
2081 copy_template(other_value
);
2084 CHARSTRING_template::~CHARSTRING_template()
2089 CHARSTRING_template
& CHARSTRING_template::operator=(template_sel other_value
)
2091 check_single_selection(other_value
);
2093 set_selection(other_value
);
2097 CHARSTRING_template
& CHARSTRING_template::operator=
2098 (const CHARSTRING
& other_value
)
2100 other_value
.must_bound("Assignment of an unbound charstring value to a "
2103 set_selection(SPECIFIC_VALUE
);
2104 single_value
= other_value
;
2108 CHARSTRING_template
& CHARSTRING_template::operator=
2109 (const CHARSTRING_ELEMENT
& other_value
)
2111 other_value
.must_bound("Assignment of an unbound charstring element to a "
2114 set_selection(SPECIFIC_VALUE
);
2115 single_value
= other_value
;
2119 CHARSTRING_template
& CHARSTRING_template::operator=
2120 (const OPTIONAL
<CHARSTRING
>& other_value
)
2123 switch (other_value
.get_selection()) {
2124 case OPTIONAL_PRESENT
:
2125 set_selection(SPECIFIC_VALUE
);
2126 single_value
= (const CHARSTRING
&)other_value
;
2129 set_selection(OMIT_VALUE
);
2132 TTCN_error("Assignment of an unbound optional field to a charstring "
2138 CHARSTRING_template
& CHARSTRING_template::operator=
2139 (const CHARSTRING_template
& other_value
)
2141 if (&other_value
!= this) {
2143 copy_template(other_value
);
2148 CHARSTRING_ELEMENT
CHARSTRING_template::operator[](int index_value
)
2150 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
2151 TTCN_error("Accessing a charstring element of a non-specific charstring "
2153 return single_value
[index_value
];
2156 CHARSTRING_ELEMENT
CHARSTRING_template::operator[](const INTEGER
& index_value
)
2158 index_value
.must_bound("Indexing a charstring template with an unbound "
2160 return (*this)[(int)index_value
];
2163 const CHARSTRING_ELEMENT
CHARSTRING_template::operator[](int index_value
) const
2165 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
2166 TTCN_error("Accessing a charstring element of a non-specific charstring "
2168 return single_value
[index_value
];
2171 const CHARSTRING_ELEMENT
CHARSTRING_template::operator[](const INTEGER
& index_value
) const
2173 index_value
.must_bound("Indexing a charstring template with an unbound "
2175 return (*this)[(int)index_value
];
2178 boolean
CHARSTRING_template::match(const CHARSTRING
& other_value
,
2179 boolean
/* legacy */) const
2181 if (!other_value
.is_bound()) return FALSE
;
2182 int value_length
= other_value
.lengthof();
2183 if (!match_length(value_length
)) return FALSE
;
2184 switch (template_selection
) {
2185 case SPECIFIC_VALUE
:
2186 return single_value
== other_value
;
2187 case STRING_PATTERN
: {
2188 if (!pattern_value
.regexp_init
) {
2189 char *posix_str
=TTCN_pattern_to_regexp(single_value
);
2190 if(posix_str
==NULL
) {
2191 TTCN_error("Cannot convert pattern \"%s\" to POSIX-equivalent.",
2192 (const char*)single_value
);
2195 //TTCN_Logger::begin_event(TTCN_DEBUG);
2196 TTCN_Logger::log_event_str("POSIX ERE equivalent of pattern ");
2198 TTCN_Logger::log_event(" is: \"%s\"", posix_str);
2199 //TTCN_Logger::end_event();
2201 int ret_val
=regcomp(&pattern_value
.posix_regexp
, posix_str
,
2202 REG_EXTENDED
|REG_NOSUB
);
2206 char msg
[ERRMSG_BUFSIZE
];
2207 regerror(ret_val
, &pattern_value
.posix_regexp
, msg
, ERRMSG_BUFSIZE
);
2208 regfree(&pattern_value
.posix_regexp
);
2209 TTCN_error("Pattern matching error: %s", msg
);
2211 pattern_value
.regexp_init
=TRUE
;
2213 int ret_val
=regexec(&pattern_value
.posix_regexp
, other_value
, 0, NULL
, 0);
2221 char msg
[ERRMSG_BUFSIZE
];
2222 regerror(ret_val
, &pattern_value
.posix_regexp
, msg
, ERRMSG_BUFSIZE
);
2223 TTCN_error("Pattern matching error: %s", msg
);
2232 case COMPLEMENTED_LIST
:
2233 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2234 if (value_list
.list_value
[i
].match(other_value
))
2235 return template_selection
== VALUE_LIST
;
2236 return template_selection
== COMPLEMENTED_LIST
;
2238 if (!value_range
.min_is_set
) TTCN_error("The lower bound is not set when "
2239 "matching with a charstring value range template.");
2240 if (!value_range
.max_is_set
) TTCN_error("The upper bound is not set when "
2241 "matching with a charstring value range template.");
2242 if (value_range
.min_value
> value_range
.max_value
)
2243 TTCN_error("The lower bound (\"%c\") is greater than the upper bound "
2244 "(\"%c\") when matching with a charstring value range template.",
2245 value_range
.min_value
, value_range
.max_value
);
2246 const char *chars_ptr
= other_value
;
2247 for (int i
= 0; i
< value_length
; i
++) {
2248 if (chars_ptr
[i
] < value_range
.min_value
||
2249 chars_ptr
[i
] > value_range
.max_value
) return FALSE
;
2254 TTCN_error("Matching with an uninitialized/unsupported charstring "
2260 const CHARSTRING
& CHARSTRING_template::valueof() const
2262 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
2263 TTCN_error("Performing valueof or send operation on a non-specific "
2264 "charstring template.");
2265 return single_value
;
2268 int CHARSTRING_template::lengthof() const
2271 boolean has_any_or_none
;
2273 TTCN_error("Performing lengthof() operation on a charstring template "
2274 "which has an ifpresent attribute.");
2275 switch (template_selection
)
2277 case SPECIFIC_VALUE
:
2278 min_length
= single_value
.lengthof();
2279 has_any_or_none
= FALSE
;
2282 TTCN_error("Performing lengthof() operation on a charstring template "
2283 "containing omit value.");
2288 has_any_or_none
= TRUE
; // max. length is infinity
2292 // error if any element does not have length or the lengths differ
2293 if (value_list
.n_values
<1)
2294 TTCN_error("Internal error: "
2295 "Performing lengthof() operation on a charstring template "
2296 "containing an empty list.");
2297 int item_length
= value_list
.list_value
[0].lengthof();
2298 for (unsigned int i
= 1; i
< value_list
.n_values
; i
++) {
2299 if (value_list
.list_value
[i
].lengthof()!=item_length
)
2300 TTCN_error("Performing lengthof() operation on a charstring template "
2301 "containing a value list with different lengths.");
2303 min_length
= item_length
;
2304 has_any_or_none
= FALSE
;
2307 case COMPLEMENTED_LIST
:
2308 TTCN_error("Performing lengthof() operation on a charstring template "
2309 "containing complemented list.");
2310 case STRING_PATTERN
:
2311 TTCN_error("Performing lengthof() operation on a charstring template "
2312 "containing a pattern is not allowed.");
2314 TTCN_error("Performing lengthof() operation on an "
2315 "uninitialized/unsupported charstring template.");
2317 return check_section_is_single(min_length
, has_any_or_none
,
2318 "length", "a", "charstring template");
2321 void CHARSTRING_template::set_type(template_sel template_type
,
2322 unsigned int list_length
)
2325 switch (template_type
) {
2327 case COMPLEMENTED_LIST
:
2328 set_selection(template_type
);
2329 value_list
.n_values
= list_length
;
2330 value_list
.list_value
= new CHARSTRING_template
[list_length
];
2333 set_selection(VALUE_RANGE
);
2334 value_range
.min_is_set
= FALSE
;
2335 value_range
.max_is_set
= FALSE
;
2338 TTCN_error("Setting an invalid type for a charstring template.");
2342 CHARSTRING_template
& CHARSTRING_template::list_item(unsigned int list_index
)
2344 if (template_selection
!= VALUE_LIST
&&
2345 template_selection
!= COMPLEMENTED_LIST
)
2346 TTCN_error("Internal error: Accessing a list element of a non-list "
2347 "charstring template.");
2348 if (list_index
>= value_list
.n_values
)
2349 TTCN_error("Internal error: Index overflow in a charstring value list "
2351 return value_list
.list_value
[list_index
];
2354 void CHARSTRING_template::set_min(const CHARSTRING
& min_value
)
2356 if (template_selection
!= VALUE_RANGE
)
2357 TTCN_error("Setting the lower bound for a non-range charstring template.");
2358 min_value
.must_bound("Setting an unbound value as lower bound in a "
2359 "charstring value range template.");
2360 int length
= min_value
.lengthof();
2361 if (length
!= 1) TTCN_error("The length of the lower bound in a "
2362 "charstring value range template must be 1 instead of %d.", length
);
2363 value_range
.min_is_set
= TRUE
;
2364 value_range
.min_value
= *(const char*)min_value
;
2365 if (value_range
.max_is_set
&& value_range
.min_value
> value_range
.max_value
)
2366 TTCN_error("The lower bound (\"%c\") in a charstring value range template "
2367 "is greater than the upper bound (\"%c\").", value_range
.min_value
,
2368 value_range
.max_value
);
2371 void CHARSTRING_template::set_max(const CHARSTRING
& max_value
)
2373 if (template_selection
!= VALUE_RANGE
)
2374 TTCN_error("Setting the upper bound for a non-range charstring template.");
2375 max_value
.must_bound("Setting an unbound value as upper bound in a "
2376 "charstring value range template.");
2377 int length
= max_value
.lengthof();
2378 if (length
!= 1) TTCN_error("The length of the upper bound in a "
2379 "charstring value range template must be 1 instead of %d.", length
);
2380 value_range
.max_is_set
= TRUE
;
2381 value_range
.max_value
= *(const char*)max_value
;
2382 if (value_range
.min_is_set
&& value_range
.min_value
> value_range
.max_value
)
2383 TTCN_error("The upper bound (\"%c\") in a charstring value range template "
2384 "is smaller than the lower bound (\"%c\").", value_range
.max_value
,
2385 value_range
.min_value
);
2388 void CHARSTRING_template::log_pattern(int n_chars
, const char *chars_ptr
)
2390 TTCN_Logger::log_event_str("pattern \"");
2391 enum { INITIAL
, BACKSLASH
, BACKSLASH_Q
, QUADRUPLE
, HASHMARK
, REPETITIONS
}
2393 for (int i
= 0; i
< n_chars
; i
++) {
2394 unsigned char c
= chars_ptr
[i
];
2395 // print the character
2399 TTCN_Logger::log_event_str("\\\"");
2402 if (state
== BACKSLASH
|| state
== BACKSLASH_Q
)
2403 TTCN_Logger::log_char('{');
2404 else TTCN_Logger::log_event_str("\\{");
2407 if (state
== BACKSLASH
|| state
== QUADRUPLE
)
2408 TTCN_Logger::log_char('}');
2409 else TTCN_Logger::log_event_str("\\}");
2412 if (state
!= INITIAL
&& state
!= BACKSLASH
) break;
2415 TTCN_Logger::log_char(c
);
2421 if (state
== INITIAL
|| state
== BACKSLASH
)
2422 TTCN_Logger::log_event_str("\\t");
2425 if (state
== INITIAL
|| state
== BACKSLASH
)
2426 TTCN_Logger::log_event_str("\\r");
2431 if (state
!= INITIAL
&& state
!= BACKSLASH
) break;
2434 TTCN_Logger::log_event("\\q{0,0,0,%u}", c
);
2453 if (c
== 'q') state
= BACKSLASH_Q
;
2454 else state
= INITIAL
;
2476 state
= REPETITIONS
;
2502 if (!isdigit(c
)) state
= INITIAL
;
2508 TTCN_Logger::log_char('"');
2511 void CHARSTRING_template::log() const
2513 switch (template_selection
) {
2514 case STRING_PATTERN
:
2515 log_pattern(single_value
.lengthof(), (const char*)single_value
);
2517 case SPECIFIC_VALUE
:
2520 case COMPLEMENTED_LIST
:
2521 TTCN_Logger::log_event_str("complement ");
2524 TTCN_Logger::log_char('(');
2525 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++) {
2526 if (i
> 0) TTCN_Logger::log_event_str(", ");
2527 value_list
.list_value
[i
].log();
2529 TTCN_Logger::log_char(')');
2532 TTCN_Logger::log_char('(');
2533 if (value_range
.min_is_set
) {
2534 if (TTCN_Logger::is_printable(value_range
.min_value
)) {
2535 TTCN_Logger::log_char('"');
2536 TTCN_Logger::log_char_escaped(value_range
.min_value
);
2537 TTCN_Logger::log_char('"');
2538 } else TTCN_Logger::log_event("char(0, 0, 0, %u)",
2539 (unsigned char)value_range
.min_value
);
2540 } else TTCN_Logger::log_event_str("<unknown lower bound>");
2541 TTCN_Logger::log_event_str(" .. ");
2542 if (value_range
.max_is_set
) {
2543 if (TTCN_Logger::is_printable(value_range
.max_value
)) {
2544 TTCN_Logger::log_char('"');
2545 TTCN_Logger::log_char_escaped(value_range
.max_value
);
2546 TTCN_Logger::log_char('"');
2547 } else TTCN_Logger::log_event("char(0, 0, 0, %u)",
2548 (unsigned char)value_range
.max_value
);
2549 } else TTCN_Logger::log_event_str("<unknown upper bound>");
2550 TTCN_Logger::log_char(')');
2559 void CHARSTRING_template::log_match(const CHARSTRING
& match_value
,
2560 boolean
/* legacy */) const
2562 if (TTCN_Logger::VERBOSITY_COMPACT
== TTCN_Logger::get_matching_verbosity()
2563 && TTCN_Logger::get_logmatch_buffer_len() != 0) {
2564 TTCN_Logger::print_logmatch_buffer();
2565 TTCN_Logger::log_event_str(" := ");
2568 TTCN_Logger::log_event_str(" with ");
2570 if (match(match_value
)) TTCN_Logger::log_event_str(" matched");
2571 else TTCN_Logger::log_event_str(" unmatched");
2574 void CHARSTRING_template::set_param(Module_Param
& param
) {
2575 param
.basic_check(Module_Param::BC_TEMPLATE
|Module_Param::BC_LIST
, "charstring template");
2576 Module_Param_Ptr mp
= ¶m
;
2577 if (param
.get_type() == Module_Param::MP_Reference
) {
2578 mp
= param
.get_referenced_param();
2580 switch (mp
->get_type()) {
2581 case Module_Param::MP_Omit
:
2584 case Module_Param::MP_Any
:
2587 case Module_Param::MP_AnyOrNone
:
2588 *this = ANY_OR_OMIT
;
2590 case Module_Param::MP_List_Template
:
2591 case Module_Param::MP_ComplementList_Template
: {
2592 CHARSTRING_template temp
;
2593 temp
.set_type(mp
->get_type() == Module_Param::MP_List_Template
?
2594 VALUE_LIST
: COMPLEMENTED_LIST
, mp
->get_size());
2595 for (size_t i
=0; i
<mp
->get_size(); i
++) {
2596 temp
.list_item(i
).set_param(*mp
->get_elem(i
));
2600 case Module_Param::MP_Charstring
:
2601 *this = CHARSTRING(mp
->get_string_size(), (char*)mp
->get_string_data());
2603 case Module_Param::MP_StringRange
: {
2604 universal_char lower_uchar
= mp
->get_lower_uchar();
2605 universal_char upper_uchar
= mp
->get_upper_uchar();
2606 if (!lower_uchar
.is_char()) param
.error("Lower bound of char range cannot be a multiple-byte character");
2607 if (!upper_uchar
.is_char()) param
.error("Upper bound of char range cannot be a multiple-byte character");
2609 set_selection(VALUE_RANGE
);
2610 value_range
.min_is_set
= TRUE
;
2611 value_range
.max_is_set
= TRUE
;
2612 value_range
.min_value
= (char)(lower_uchar
.uc_cell
);
2613 value_range
.max_value
= (char)(upper_uchar
.uc_cell
);
2615 case Module_Param::MP_Pattern
:
2617 single_value
= CHARSTRING(mp
->get_pattern());
2618 pattern_value
.regexp_init
= FALSE
;
2619 set_selection(STRING_PATTERN
);
2621 case Module_Param::MP_Expression
:
2622 if (mp
->get_expr_type() == Module_Param::EXPR_CONCATENATE
) {
2623 // only allow string patterns for the first operand
2624 CHARSTRING operand1
, operand2
, result
;
2625 boolean is_pattern
= operand1
.set_param_internal(*mp
->get_operand1(), TRUE
);
2626 operand2
.set_param(*mp
->get_operand2());
2627 result
= operand1
+ operand2
;
2630 single_value
= result
;
2631 pattern_value
.regexp_init
= FALSE
;
2632 set_selection(STRING_PATTERN
);
2639 param
.expr_type_error("a charstring");
2643 param
.type_error("charstring template");
2645 is_ifpresent
= param
.get_ifpresent() || mp
->get_ifpresent();
2646 if (param
.get_length_restriction() != NULL
) {
2647 set_length_range(param
);
2650 set_length_range(*mp
);
2654 Module_Param
* CHARSTRING_template::get_param(Module_Param_Name
& param_name
) const
2656 Module_Param
* mp
= NULL
;
2657 switch (template_selection
) {
2658 case UNINITIALIZED_TEMPLATE
:
2659 mp
= new Module_Param_Unbound();
2662 mp
= new Module_Param_Omit();
2665 mp
= new Module_Param_Any();
2668 mp
= new Module_Param_AnyOrNone();
2670 case SPECIFIC_VALUE
:
2671 mp
= single_value
.get_param(param_name
);
2674 case COMPLEMENTED_LIST
: {
2675 if (template_selection
== VALUE_LIST
) {
2676 mp
= new Module_Param_List_Template();
2679 mp
= new Module_Param_ComplementList_Template();
2681 for (size_t i
= 0; i
< value_list
.n_values
; ++i
) {
2682 mp
->add_elem(value_list
.list_value
[i
].get_param(param_name
));
2686 universal_char lower_bound
= { 0, 0, 0, (unsigned char)value_range
.min_value
};
2687 universal_char upper_bound
= { 0, 0, 0, (unsigned char)value_range
.max_value
};
2688 mp
= new Module_Param_StringRange(lower_bound
, upper_bound
);
2690 case STRING_PATTERN
:
2691 mp
= new Module_Param_Pattern(mcopystr(single_value
));
2697 mp
->set_ifpresent();
2699 mp
->set_length_restriction(get_length_range());
2703 void CHARSTRING_template::encode_text(Text_Buf
& text_buf
) const
2705 encode_text_restricted(text_buf
);
2706 switch (template_selection
) {
2711 case SPECIFIC_VALUE
:
2712 case STRING_PATTERN
:
2713 single_value
.encode_text(text_buf
);
2716 case COMPLEMENTED_LIST
:
2717 text_buf
.push_int(value_list
.n_values
);
2718 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2719 value_list
.list_value
[i
].encode_text(text_buf
);
2722 if (!value_range
.min_is_set
) TTCN_error("Text encoder: The lower bound is "
2723 "not set in a charstring value range template.");
2724 if (!value_range
.max_is_set
) TTCN_error("Text encoder: The upper bound is "
2725 "not set in a charstring value range template.");
2726 text_buf
.push_raw(1, &value_range
.min_value
);
2727 text_buf
.push_raw(1, &value_range
.max_value
);
2730 TTCN_error("Text encoder: Encoding an uninitialized/unsupported "
2731 "charstring template.");
2735 void CHARSTRING_template::decode_text(Text_Buf
& text_buf
)
2738 decode_text_restricted(text_buf
);
2739 switch (template_selection
) {
2744 case STRING_PATTERN
:
2745 pattern_value
.regexp_init
=FALSE
;
2747 case SPECIFIC_VALUE
:
2748 single_value
.decode_text(text_buf
);
2751 case COMPLEMENTED_LIST
:
2752 value_list
.n_values
= text_buf
.pull_int().get_val();
2753 value_list
.list_value
= new CHARSTRING_template
[value_list
.n_values
];
2754 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
2755 value_list
.list_value
[i
].decode_text(text_buf
);
2758 text_buf
.pull_raw(1, &value_range
.min_value
);
2759 text_buf
.pull_raw(1, &value_range
.max_value
);
2760 if (value_range
.min_value
> value_range
.max_value
)
2761 TTCN_error("Text decoder: The received lower bound is greater than the "
2762 "upper bound in a charstring value range template.");
2763 value_range
.min_is_set
= TRUE
;
2764 value_range
.max_is_set
= TRUE
;
2767 TTCN_error("Text decoder: An unknown/unsupported selection was "
2768 "received for a charstring template.");
2772 boolean
CHARSTRING_template::is_present(boolean legacy
/* = FALSE */) const
2774 if (template_selection
==UNINITIALIZED_TEMPLATE
) return FALSE
;
2775 return !match_omit(legacy
);
2778 boolean
CHARSTRING_template::match_omit(boolean legacy
/* = FALSE */) const
2780 if (is_ifpresent
) return TRUE
;
2781 switch (template_selection
) {
2786 case COMPLEMENTED_LIST
:
2788 // legacy behavior: 'omit' can appear in the value/complement list
2789 for (unsigned int i
=0; i
<value_list
.n_values
; i
++)
2790 if (value_list
.list_value
[i
].match_omit())
2791 return template_selection
==VALUE_LIST
;
2792 return template_selection
==COMPLEMENTED_LIST
;
2794 // else fall through
2801 #ifndef TITAN_RUNTIME_2
2802 void CHARSTRING_template::check_restriction(template_res t_res
, const char* t_name
,
2803 boolean legacy
/* = FALSE */) const
2805 if (template_selection
==UNINITIALIZED_TEMPLATE
) return;
2806 switch ((t_name
&&(t_res
==TR_VALUE
))?TR_OMIT
:t_res
) {
2808 if (!is_ifpresent
&& template_selection
==SPECIFIC_VALUE
) return;
2811 if (!is_ifpresent
&& (template_selection
==OMIT_VALUE
||
2812 template_selection
==SPECIFIC_VALUE
)) return;
2815 if (!match_omit(legacy
)) return;
2820 TTCN_error("Restriction `%s' on template of type %s violated.",
2821 get_res_name(t_res
), t_name
? t_name
: "charstring");
2825 const CHARSTRING
& CHARSTRING_template::get_single_value() const {
2826 switch (template_selection
) {
2827 case STRING_PATTERN
:
2828 case SPECIFIC_VALUE
:
2831 TTCN_error("This template does not have single value.");
2833 return single_value
;