Addfunc.cc 115 KB
Newer Older
Elemer Lelik's avatar
Elemer Lelik committed
1
/******************************************************************************
balaskoa's avatar
balaskoa committed
2
 * Copyright (c) 2000-2020 Ericsson Telecom AB
Elemer Lelik's avatar
Elemer Lelik committed
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v2.0
Elemer Lelik's avatar
Elemer Lelik committed
5
 * which accompanies this distribution, and is available at
6
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
Elemer Lelik's avatar
Elemer Lelik committed
7
8
9
10
11
12
13
14
15
16
 *
 * Contributors:
 *   Baji, Laszlo
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Delic, Adam
 *   Feher, Csaba
 *   Forstner, Matyas
 *   Kovacs, Ferenc
 *   Raduly, Csaba
17
 *   Szabo, Bence Janos
Elemer Lelik's avatar
Elemer Lelik committed
18
 *   Szabo, Janos Zoltan – initial implementation
19
 *   Szalai, Gabor
Elemer Lelik's avatar
Elemer Lelik committed
20
21
22
 *   Zalanyi, Balazs Andor
 *
 ******************************************************************************/
Elemer Lelik's avatar
Elemer Lelik committed
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "Addfunc.hh"

#include "../common/memory.h"
#include "../common/pattern.hh"
#include "Integer.hh"
#include "Float.hh"
#include "Bitstring.hh"
#include "Hexstring.hh"
#include "Octetstring.hh"
#include "Charstring.hh"
#include "Universal_charstring.hh"
#include "String_struct.hh"
#include "Logger.hh"
#include "Snapshot.hh"
#include "TitanLoggerApi.hh"
38
#include "../common/UnicharPattern.hh"
39
#include "JSON.hh"
Elemer Lelik's avatar
Elemer Lelik committed
40
41
42
43
44
45
46
47
48

#include <openssl/bn.h>

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
49
#include <locale.h>
Elemer Lelik's avatar
Elemer Lelik committed
50
51
52

#define ERRMSG_BUFSIZE 512

53
54
55
56
#ifndef INFINITY
#define INFINITY (DBL_MAX*DBL_MAX)
#endif

Elemer Lelik's avatar
Elemer Lelik committed
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// table to reverse the hex digits within an octet
// input: ABCDEFGH, output: DCBAHGFE
static const unsigned char nibble_reverse_table[] =
{
0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e,
0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f,
0x80, 0x88, 0x84, 0x8c, 0x82, 0x8a, 0x86, 0x8e,
0x81, 0x89, 0x85, 0x8d, 0x83, 0x8b, 0x87, 0x8f,
0x40, 0x48, 0x44, 0x4c, 0x42, 0x4a, 0x46, 0x4e,
0x41, 0x49, 0x45, 0x4d, 0x43, 0x4b, 0x47, 0x4f,
0xc0, 0xc8, 0xc4, 0xcc, 0xc2, 0xca, 0xc6, 0xce,
0xc1, 0xc9, 0xc5, 0xcd, 0xc3, 0xcb, 0xc7, 0xcf,
0x20, 0x28, 0x24, 0x2c, 0x22, 0x2a, 0x26, 0x2e,
0x21, 0x29, 0x25, 0x2d, 0x23, 0x2b, 0x27, 0x2f,
0xa0, 0xa8, 0xa4, 0xac, 0xa2, 0xaa, 0xa6, 0xae,
0xa1, 0xa9, 0xa5, 0xad, 0xa3, 0xab, 0xa7, 0xaf,
0x60, 0x68, 0x64, 0x6c, 0x62, 0x6a, 0x66, 0x6e,
0x61, 0x69, 0x65, 0x6d, 0x63, 0x6b, 0x67, 0x6f,
0xe0, 0xe8, 0xe4, 0xec, 0xe2, 0xea, 0xe6, 0xee,
0xe1, 0xe9, 0xe5, 0xed, 0xe3, 0xeb, 0xe7, 0xef,
0x10, 0x18, 0x14, 0x1c, 0x12, 0x1a, 0x16, 0x1e,
0x11, 0x19, 0x15, 0x1d, 0x13, 0x1b, 0x17, 0x1f,
0x90, 0x98, 0x94, 0x9c, 0x92, 0x9a, 0x96, 0x9e,
0x91, 0x99, 0x95, 0x9d, 0x93, 0x9b, 0x97, 0x9f,
0x50, 0x58, 0x54, 0x5c, 0x52, 0x5a, 0x56, 0x5e,
0x51, 0x59, 0x55, 0x5d, 0x53, 0x5b, 0x57, 0x5f,
0xd0, 0xd8, 0xd4, 0xdc, 0xd2, 0xda, 0xd6, 0xde,
0xd1, 0xd9, 0xd5, 0xdd, 0xd3, 0xdb, 0xd7, 0xdf,
0x30, 0x38, 0x34, 0x3c, 0x32, 0x3a, 0x36, 0x3e,
0x31, 0x39, 0x35, 0x3d, 0x33, 0x3b, 0x37, 0x3f,
0xb0, 0xb8, 0xb4, 0xbc, 0xb2, 0xba, 0xb6, 0xbe,
0xb1, 0xb9, 0xb5, 0xbd, 0xb3, 0xbb, 0xb7, 0xbf,
0x70, 0x78, 0x74, 0x7c, 0x72, 0x7a, 0x76, 0x7e,
0x71, 0x79, 0x75, 0x7d, 0x73, 0x7b, 0x77, 0x7f,
0xf0, 0xf8, 0xf4, 0xfc, 0xf2, 0xfa, 0xf6, 0xfe,
0xf1, 0xf9, 0xf5, 0xfd, 0xf3, 0xfb, 0xf7, 0xff
};

// table to swap the hex digits within an octet
// input: ABCDEFGH, output: EFGHABCD
static const unsigned char nibble_swap_table[] =
{
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1, 0xf1,
0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
0x82, 0x92, 0xa2, 0xb2, 0xc2, 0xd2, 0xe2, 0xf2,
0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3, 0xe3, 0xf3,
0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4,
0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5,
0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6,
0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7,
0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8,
0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9,
0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a,
0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa,
0x0b, 0x1b, 0x2b, 0x3b, 0x4b, 0x5b, 0x6b, 0x7b,
0x8b, 0x9b, 0xab, 0xbb, 0xcb, 0xdb, 0xeb, 0xfb,
0x0c, 0x1c, 0x2c, 0x3c, 0x4c, 0x5c, 0x6c, 0x7c,
0x8c, 0x9c, 0xac, 0xbc, 0xcc, 0xdc, 0xec, 0xfc,
0x0d, 0x1d, 0x2d, 0x3d, 0x4d, 0x5d, 0x6d, 0x7d,
0x8d, 0x9d, 0xad, 0xbd, 0xcd, 0xdd, 0xed, 0xfd,
0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e,
0x8e, 0x9e, 0xae, 0xbe, 0xce, 0xde, 0xee, 0xfe,
0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f,
0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff
};

// table to reverse the bits within an octet
// input: ABCDEFGH, output: HGFEDCBA
static const unsigned char bit_reverse_table[] =
{
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
};

static const unsigned char UTF8_BOM[]    = {0xef, 0xbb, 0xbf};
static const unsigned char UTF16BE_BOM[] = {0xfe, 0xff};
static const unsigned char UTF16LE_BOM[] = {0xff, 0xfe};
static const unsigned char UTF32BE_BOM[] = {0x00, 0x00, 0xfe, 0xff};
static const unsigned char UTF32LE_BOM[] = {0xff, 0xfe, 0x00, 0x00};

// Functions for internal purposes

unsigned char char_to_hexdigit(char c)
{
  if (c >= '0' && c <= '9') return c - '0';
  else if (c >= 'A' && c <= 'F') return c - 'A' + 10;
  else if (c >= 'a' && c <= 'f') return c - 'a' + 10;
  else return 0xFF;
}

char hexdigit_to_char(unsigned char hexdigit)
{
  if (hexdigit < 10) return '0' + hexdigit;
  else if (hexdigit < 16) return 'A' + hexdigit - 10;
  else return '\0';
}

static boolean is_whitespace(char c)
{
  switch (c) {
  case ' ':
  case '\t':
  case '\r':
  case '\n':
  case '\v':
  case '\f':
    return TRUE;
  default:
    return FALSE;
  }
}

static CharCoding::CharCodingType is_ascii ( const OCTETSTRING& ostr )
{
  const unsigned char nonASCII = 1 << 7;// MSB is 1 in case of non ASCII character  
  CharCoding::CharCodingType ret = CharCoding::ASCII;
  const unsigned char* strptr = (const unsigned char*)ostr;
  for (int i = 0; i < ostr.lengthof(); ++i) {
    if ( strptr[i] & nonASCII) {
      ret = CharCoding::UNKNOWN;
      break;
    }
  }
  return ret;
}

static CharCoding::CharCodingType is_utf8 ( const OCTETSTRING& ostr )
{
225
226
  const unsigned char MSB = 1 << 7; // MSB is 1 in case of non ASCII character  
  const unsigned char MSBmin1 = 1 << 6; // 0100 0000   
Elemer Lelik's avatar
Elemer Lelik committed
227
228
229
230
231
232
  int i = 0;
  const unsigned char* strptr = (const unsigned char*)ostr;
  //  std::cout << "UTF-8 strptr" << strptr << std::endl;  
  while (ostr.lengthof() > i) {
    if ( strptr[i] & MSB) { // non ASCII char
  // std::cout << "UTF-8 strptr[" << i << "]: " << std::hex << (int)strptr[i] << std::endl;
233
    unsigned char maskUTF8 = 1 << 6; // 111x xxxx shows how many additional bytes are there
Elemer Lelik's avatar
Elemer Lelik committed
234
235
236
237
238
239
240
241
242
243
      if (!(strptr[i] & maskUTF8)) return CharCoding::UNKNOWN; // accepted 11xxx xxxx but received 10xx xxxx
      unsigned int noofUTF8 = 0; // 11xx xxxxx -> 2 bytes, 111x xxxxx -> 3 bytes , 1111 xxxxx -> 4 bytes in UTF-8
      while (strptr[i] & maskUTF8) {
        ++noofUTF8;
        maskUTF8 >>= 1; // shift right the mask
      }
  // the second and third (and so on) UTF-8 byte looks like 10xx xxxx      
      while (0 < noofUTF8 ) {
        ++i;
  //std::cout << "mask & strptr[" << i << "] " << std::hex << (int)strptr[i]  << std::endl;
244
        if (i >= ostr.lengthof() || !(strptr[i] & MSB) || (strptr[i] & MSBmin1)) { // if not like this: 10xx xxxx
Elemer Lelik's avatar
Elemer Lelik committed
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
          return CharCoding::UNKNOWN;
        }
        --noofUTF8;
      }
    }
    ++i;
  }
  return CharCoding::UTF_8;
}

// Additional predefined functions defined in Annex C of ES 101 873-1

// C.1 - int2char

CHARSTRING int2char(int value)
{
  if (value < 0 || value > 127) TTCN_error("The argument of function "
    "int2char() is %d, which is outside the allowed range 0 .. 127.",
    value);
  return CHARSTRING((char)value);
}

CHARSTRING int2char(const INTEGER& value)
{
  value.must_bound("The argument of function int2char() is an unbound "
    "integer value.");
  const int_val_t& ivt = value.get_val();
  if (ivt < 0 || ivt > 127) {
    char *value_str = ivt.as_string();
274
275
276
277
278
279
280
281
    try {
      TTCN_error("The argument of function int2char() is %s, "
        "which is outside the allowed range 0 .. 127.", value_str);
    }
    catch (const TC_Error&) {
      Free(value_str);
      throw;
    }
Elemer Lelik's avatar
Elemer Lelik committed
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  }
  return CHARSTRING((char)((int)value));
}

// C.2 - int2unichar

UNIVERSAL_CHARSTRING int2unichar(int value)
{
  if (value < 0 || value > 2147483647) TTCN_error("The argument of function "
    "int2unichar() is %d, which outside the allowed range 0 .. 2147483647.",
    value);
  return UNIVERSAL_CHARSTRING(value >> 24, (value >> 16) & 0xFF,
    (value >> 8) & 0xFF, value & 0xFF);
}

UNIVERSAL_CHARSTRING int2unichar(const INTEGER& value)
{
  value.must_bound("The argument of function int2unichar() is an unbound "
    "integer value.");
  const int_val_t& ivt = value.get_val();
  if (ivt < 0 || ivt > 2147483647) {
    char *value_str = ivt.as_string();
304
305
306
307
308
309
310
311
    try {
      TTCN_error("The argument of function int2unichar() is %s, "
        "which outside the allowed range 0 .. 2147483647.", value_str);
    }
    catch (const TC_Error&) {
      Free(value_str);
      throw;
    }
Elemer Lelik's avatar
Elemer Lelik committed
312
313
314
315
316
317
318
319
320
321
322
323
324
  }
  return int2unichar((int)value);
}

// C.3 - int2bit

BITSTRING int2bit(const INTEGER& value, int length)
{
  value.must_bound("The first argument (value) of function int2bit() is "
    "an unbound integer value.");
  int_val_t tmp_value(value.get_val());
  if (tmp_value < 0) {
    char *value_str = tmp_value.as_string();
325
326
327
328
329
330
331
332
    try {
      TTCN_error("The first argument (value) of function "
        "int2bit() is a negative integer value: %s.", value_str);
    }
    catch (const TC_Error&) {
      Free(value_str);
      throw;
    }
Elemer Lelik's avatar
Elemer Lelik committed
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  }
  if (length < 0) TTCN_error("The second argument (length) of function "
    "int2bit() is a negative integer value: %d.", length);
  BITSTRING ret_val(length);
  unsigned char *bits_ptr = ret_val.val_ptr->bits_ptr;
  // clearing all bits in the result
  memset(bits_ptr, '\0', (length + 7) / 8);
  // we are setting some bits to 1 so we may stop if there are no more 1 bits
  // in the input
  for (int i = length - 1; tmp_value != 0 && i >= 0; i--) {
    if ((tmp_value & 1).get_val()) bits_ptr[i / 8] |= (1 << (i % 8));
    tmp_value >>= 1;
  }
  if (tmp_value != 0) {
347
348
349
350
351
    int i = 0;
    while(tmp_value != 0) {
      tmp_value >>= 1;
      i++;
    }
Elemer Lelik's avatar
Elemer Lelik committed
352
    char *value_str = value.get_val().as_string(); // not tmp_value!
353
354
355
356
357
358
359
360
361
    try {
      TTCN_error("The first argument of function int2bit(), which is %s, "
        "does not fit in %d bit%s, needs at least %d.", value_str, length,
        length > 1 ? "s" :"", length + i);
    }
    catch (const TC_Error&) {
      Free(value_str);
      throw;
    }
Elemer Lelik's avatar
Elemer Lelik committed
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
  }
  return ret_val;
}

BITSTRING int2bit(int value, const INTEGER& length)
{
  length.must_bound("The second argument (length) of function int2bit() is "
    "an unbound integer value.");
  return int2bit(INTEGER(value), (int)length);
}

BITSTRING int2bit(int value, int length)
{
  return int2bit(INTEGER(value), length);
}

BITSTRING int2bit(const INTEGER& value, const INTEGER& length)
{
  value.must_bound("The first argument (value) of function int2bit() is "
    "an unbound integer value.");
  length.must_bound("The second argument (length) of function int2bit() is "
    "an unbound integer value.");
  return int2bit(value, (int)length);
}

// C.4 - int2hex

HEXSTRING int2hex(const INTEGER& value, int length)
{
  value.must_bound("The first argument (value) of function int2hex() is "
    "an unbound integer value.");
  int_val_t tmp_value(value.get_val());
  if (value < 0) {
    char *value_str = tmp_value.as_string();
396
397
398
399
400
401
402
403
    try {
      TTCN_error("The first argument (value) of function int2hex() is a "
        "negative integer value: %s.", value_str);
    }
    catch (const TC_Error&) {
      Free(value_str);
      throw;
    }
Elemer Lelik's avatar
Elemer Lelik committed
404
405
406
407
408
409
410
411
412
413
414
415
416
417
  }
  if (length < 0) TTCN_error("The second argument (length) of function "
    "int2hex() is a negative integer value: %d.", length);
  HEXSTRING ret_val(length);
  unsigned char *nibbles_ptr = ret_val.val_ptr->nibbles_ptr;
  // clearing the unused bits in the last octet if necessary
  if (length % 2) nibbles_ptr[length / 2] = '\0';
  for (int i = length - 1; i >= 0; i--) {
    if (i % 2) nibbles_ptr[i / 2] = (tmp_value & 0xF).get_val() << 4;
    else nibbles_ptr[i / 2] |= (tmp_value & 0xF).get_val();
    tmp_value >>= 4;
  }
  if (tmp_value != 0) {
    char *value_str = value.get_val().as_string(); // not tmp_value!
418
419
420
421
422
423
424
425
426
    try {
      TTCN_error("The first argument of function int2hex(), which is %s, "
        "does not fit in %d hexadecimal digit%s.", value_str, length,
        length > 1 ? "s" :"");
    }
    catch (const TC_Error&) {
      Free(value_str); 
      throw;
    }
Elemer Lelik's avatar
Elemer Lelik committed
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
  }
  return ret_val;
}

HEXSTRING int2hex(int value, const INTEGER& length)
{
  length.must_bound("The second argument (length) of function int2hex() is "
    "an unbound integer value.");
  return int2hex(INTEGER(value), (int)length);
}

HEXSTRING int2hex(int value, int length)
{
  return int2hex(INTEGER(value), length);
}

HEXSTRING int2hex(const INTEGER& value, const INTEGER& length)
{
  value.must_bound("The first argument (value) of function int2hex() is "
    "an unbound integer value.");
  length.must_bound("The second argument (length) of function int2hex() is "
    "an unbound integer value.");
  return int2hex(value, (int)length);
}

// C.5 - int2oct

OCTETSTRING int2oct(int value, int length)
{
  if (value < 0) TTCN_error("The first argument (value) of function "
    "int2oct() is a negative integer value: %d.", value);
  if (length < 0) TTCN_error("The second argument (length) of function "
    "int2oct() is a negative integer value: %d.", length);
  OCTETSTRING ret_val(length);
  unsigned char *octets_ptr = ret_val.val_ptr->octets_ptr;
  unsigned int tmp_value = value;
  for (int i = length - 1; i >= 0; i--) {
    octets_ptr[i] = tmp_value & 0xFF;
    tmp_value >>= 8;
  }
  if (tmp_value != 0) {
    TTCN_error("The first argument of function int2oct(), which is %d, "
      "does not fit in %d octet%s.", value, length,
      length > 1 ? "s" :"");
  }
  return ret_val;
}

OCTETSTRING int2oct(int value, const INTEGER& length)
{
  length.must_bound("The second argument (length) of function int2oct() is "
    "an unbound integer value.");
  return int2oct(value, (int)length);
}

OCTETSTRING int2oct(const INTEGER& value, int length)
{
  value.must_bound("The first argument (value) of function int2oct() is "
    "an unbound integer value.");
  const int_val_t& value_int = value.get_val();
  char *tmp_str = value_int.as_string();
  CHARSTRING value_str(tmp_str);
  Free(tmp_str);
  if (value_int.is_native()) {
    return int2oct((int)value, length);
  } else {
    if (value_int < 0) TTCN_error("The first argument (value) of function "
      "int2oct() is a negative integer value: %s.",
      (const char *)value_str);
    if (length < 0) TTCN_error("The second argument (length) of function "
      "int2oct() is a negative integer value: %d.", length);
    BIGNUM *value_tmp = BN_dup(value_int.get_val_openssl());
    int bytes = BN_num_bytes(value_tmp);
    if (bytes > length) {
      BN_free(value_tmp);
      TTCN_error("The first argument of function int2oct(), which is %s, "
        "does not fit in %d octet%s.", (const char *)value_str, length,
        length > 1 ? "s" : "");
    } else {
506
507
      OCTETSTRING ret_val(length);
      unsigned char *octets_ptr = ret_val.val_ptr->octets_ptr;
508
509
      unsigned char* tmp = (unsigned char*)Malloc(bytes * sizeof(unsigned char));
      BN_bn2bin(value_tmp, tmp);
Elemer Lelik's avatar
Elemer Lelik committed
510
      for (int i = length - 1; i >= 0; i--) {
511
512
        if (bytes-length+i >= 0) {
          octets_ptr[i] = tmp[bytes-length+i] & 0xff;
Elemer Lelik's avatar
Elemer Lelik committed
513
514
515
516
517
518
519
        }
        else { // we used up all of the bignum; zero the beginning and quit
          memset(octets_ptr, 0, i+1);
          break;
        }
      }
      BN_free(value_tmp);
520
      Free(tmp);
Elemer Lelik's avatar
Elemer Lelik committed
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
      return ret_val;
    }
  }
}

OCTETSTRING int2oct(const INTEGER& value, const INTEGER& length)
{
  value.must_bound("The first argument (value) of function int2oct() is an "
    "unbound integer value.");
  length.must_bound("The second argument (length) of function int2oct() is "
    "an unbound integer value.");
  const int_val_t& value_int = value.get_val();
  if (value_int.is_native()) return int2oct(value_int.get_val(), (int)length);
  return int2oct(value, (int)length);
}

// C.6 - int2str

CHARSTRING int2str(int value)
{
  char str_buf[64];
  int str_len = snprintf(str_buf, sizeof(str_buf), "%d", value);
  if (str_len < 0 || str_len >= (int)sizeof(str_buf)) {
    TTCN_error("Internal error: system call snprintf() returned "
      "unexpected status code %d when converting value %d in function "
      "int2str().", str_len, value);
  }
  return CHARSTRING(str_len, str_buf);
}

CHARSTRING int2str(const INTEGER& value)
{
  value.must_bound("The argument of function int2str() is an unbound "
    "integer value.");
  char *value_tmp = value.get_val().as_string();
  CHARSTRING value_str(value_tmp);
  Free(value_tmp);
  return value_str;
}

// C.7 - int2float

double int2float(int value)
{
  return (double)value;
}

double int2float(const INTEGER& value)
{
  value.must_bound("The argument of function int2float() is an unbound "
    "integer value.");
  return value.get_val().to_real();
}

// C.8 - float2int

INTEGER float2int(double value)
{
  if (value >= (double)INT_MIN && value <= (double)INT_MAX) return (int)value;
  // DBL_MAX has 316 digits including the trailing 0-s on x86_64.
  char buf[512] = "";
  snprintf(buf, 511, "%f", value);
  char *dot = strchr(buf, '.');
  if (!dot) TTCN_error("Conversion of float value `%f' to integer failed", value);
  else memset(dot, 0, sizeof(buf) - (dot - buf));
  return INTEGER(buf);
}

INTEGER float2int(const FLOAT& value)
{
  value.must_bound("The argument of function float2int() is an unbound float "
    "value.");
  return float2int((double)value);
}

// C.9 - char2int

int char2int(char value)
{
  unsigned char uchar_value = value;
  if (uchar_value > 127) TTCN_error("The argument of function "
    "char2int() contains a character with character code %u, which is "
    "outside the allowed range 0 .. 127.", uchar_value);
  return uchar_value;
}

int char2int(const char *value)
{
609
610
  if (value == NULL) TTCN_error("The length of the argument in function "
    "char2int() must be exactly 1 instead of 0.");
Elemer Lelik's avatar
Elemer Lelik committed
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
  int value_length = strlen(value);
  if (value_length != 1) TTCN_error("The length of the argument in function "
    "char2int() must be exactly 1 instead of %d.", value_length);
  return char2int(value[0]);
}

int char2int(const CHARSTRING& value)
{
  value.must_bound("The argument of function char2int() is an unbound "
    "charstring value.");
  int value_length = value.lengthof();
  if (value_length != 1) TTCN_error("The length of the argument in function "
    "char2int() must be exactly 1 instead of %d.", value_length);
  return char2int(((const char*)value)[0]);
}

int char2int(const CHARSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function char2int() is an unbound "
    "charstring element.");
  return char2int(value.get_char());
}

// C.10 - char2oct

OCTETSTRING char2oct(const char *value)
{
  if (value == NULL) return OCTETSTRING(0, NULL);
  else return OCTETSTRING(strlen(value), (const unsigned char*)value);
}

OCTETSTRING char2oct(const CHARSTRING& value)
{
  value.must_bound("The argument of function char2oct() is an unbound "
    "charstring value.");
  return OCTETSTRING(value.lengthof(),
    (const unsigned char*)(const char*)value);
}

OCTETSTRING char2oct(const CHARSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function char2oct() is an unbound "
    "charstring element.");
  unsigned char octet = value.get_char();
  return OCTETSTRING(1, &octet);
}

// C.11 - unichar2int

int unichar2int(const universal_char& value)
{
  if (value.uc_group > 127) TTCN_error("The argument of function "
    "unichar2int() is the invalid quadruple char(%u, %u, %u, %u), the "
    "first number of which is outside the allowed range 0 .. 127.",
    value.uc_group, value.uc_plane, value.uc_row, value.uc_cell);
  int result = (value.uc_group << 24) | (value.uc_plane << 16) |
    (value.uc_row << 8) | value.uc_cell;
  return result;
}

int unichar2int(const UNIVERSAL_CHARSTRING& value)
{
  value.must_bound("The argument of function unichar2int() is an unbound "
    "universal charstring value.");
  int value_length = value.lengthof();
  if (value_length != 1) TTCN_error("The length of the argument in function "
    "unichar2int() must be exactly 1 instead of %d.", value_length);
  return unichar2int(((const universal_char*)value)[0]);
}

int unichar2int(const UNIVERSAL_CHARSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function unichar2int() is an unbound "
    "universal charstring element.");
  return unichar2int(value.get_uchar());
}

// C.12 - bit2int

INTEGER bit2int(const BITSTRING& value)
{
  value.must_bound("The argument of function bit2int() is an unbound "
    "bitstring value.");
  int n_bits = value.lengthof();
  const unsigned char *bit_ptr = (const unsigned char *)value;
  // skip the leading zero bits
  int start_index;
  for (start_index = 0; start_index < n_bits; start_index++)
    if (bit_ptr[start_index / 8] & (1 << (start_index % 8))) break;
  // do the conversion
  int_val_t ret_val((RInt)0);
  for (int i = start_index; i < n_bits; i++) {
    ret_val <<= 1;
    if (bit_ptr[i / 8] & (1 << (i % 8))) ret_val += 1;
  }
  if (ret_val.is_native()) return INTEGER(ret_val.get_val());
  else return INTEGER(BN_dup(ret_val.get_val_openssl()));
}

INTEGER bit2int(const BITSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function bit2int() is an unbound "
    "bitstring element.");
  return INTEGER(value.get_bit() ? 1 : 0);
}

// C.13 - bit2hex

HEXSTRING bit2hex(const BITSTRING& value)
{
  value.must_bound("The argument of function bit2hex() is an unbound "
    "bitstring value.");
  int n_bits = value.lengthof();
  int n_nibbles = (n_bits + 3) / 4;
  int padding_bits = 4 * n_nibbles - n_bits;
  const unsigned char *bits_ptr = (const unsigned char *)value;
  HEXSTRING ret_val(n_nibbles);
  unsigned char *nibbles_ptr = ret_val.val_ptr->nibbles_ptr;
  memset(nibbles_ptr, '\0', (n_nibbles + 1) / 2);
  for (int i = 0; i < n_bits; i++) {
    if (bits_ptr[i / 8] & (1 << (i % 8))) {
      nibbles_ptr[(i + padding_bits) / 8] |= 0x80 >>
        ((i + padding_bits + 4) % 8);
    }
  }
  return ret_val;
}

HEXSTRING bit2hex(const BITSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function bit2hex() is an unbound "
    "bitstring element.");
  unsigned char nibble = value.get_bit() ? 0x01 : 0x00;
  return HEXSTRING(1, &nibble);
}

// C.14 - bit2oct

OCTETSTRING bit2oct(const BITSTRING& value)
{
  value.must_bound("The argument of function bit2oct() is an unbound "
    "bitstring value.");
  int n_bits = value.lengthof();
  int n_octets = (n_bits + 7) / 8;
  int padding_bits = 8 * n_octets - n_bits;
  const unsigned char *bits_ptr = (const unsigned char *)value;
  OCTETSTRING ret_val(n_octets);
  unsigned char *octets_ptr = ret_val.val_ptr->octets_ptr;
  memset(octets_ptr, '\0', n_octets);
  for (int i = 0; i < n_bits; i++) {
    if (bits_ptr[i / 8] & (1 << (i % 8))) {
      octets_ptr[(i + padding_bits) / 8] |= 0x80 >>
        ((i + padding_bits) % 8);
    }
  }
  return ret_val;
}

OCTETSTRING bit2oct(const BITSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function bit2oct() is an unbound "
    "bitstring element.");
  unsigned char octet = value.get_bit() ? 0x01 : 0x00;
  return OCTETSTRING(1, &octet);
}

// C.15 - bit2str

CHARSTRING bit2str(const BITSTRING& value)
{
  value.must_bound("The argument of function bit2str() is an unbound "
    "bitstring value.");
  int n_bits = value.lengthof();
  const unsigned char *bits_ptr = (const unsigned char*)value;
  CHARSTRING ret_val(n_bits);
  char *chars_ptr = ret_val.val_ptr->chars_ptr;
  for (int i = 0; i < n_bits; i++) {
    if (bits_ptr[i / 8] & (1 << (i % 8))) chars_ptr[i] = '1';
    else chars_ptr[i] = '0';
  }
  return ret_val;
}

CHARSTRING bit2str(const BITSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function bit2str() is an unbound "
    "bitstring element.");
  return CHARSTRING(value.get_bit() ? '1' : '0');
}

// C.16 - hex2int

INTEGER hex2int(const HEXSTRING& value)
{
  value.must_bound("The argument of function hex2int() is an unbound "
    "hexstring value.");
  int n_nibbles = value.lengthof();
  const unsigned char *nibble_ptr = (const unsigned char *)value;
  // skip the leading zero hex digits
  int start_index;
  for (start_index = 0; start_index < n_nibbles; start_index++) {
    unsigned char mask = start_index % 2 ? 0xF0 : 0x0F;
    if (nibble_ptr[start_index / 2] & mask) break;
  }
  // do the conversion
  int_val_t ret_val((RInt)0);
  for (int i = start_index; i < n_nibbles; i++) {
    ret_val <<= 4;
    if (i % 2) ret_val += nibble_ptr[i / 2] >> 4;
    else ret_val += nibble_ptr[i / 2] & 0x0F;
  }
  if (ret_val.is_native()) return INTEGER(ret_val.get_val());
  else return INTEGER(BN_dup(ret_val.get_val_openssl()));
}

INTEGER hex2int(const HEXSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function hex2int() is an unbound "
    "hexstring element.");
  return INTEGER(value.get_nibble());
}

// C.17 - hex2bit

BITSTRING hex2bit(const HEXSTRING& value)
{
  value.must_bound("The argument of function hex2bit() is an unbound "
    "hexstring value.");
  int n_nibbles = value.lengthof();
  const unsigned char *nibbles_ptr = (const unsigned char *)value;
  BITSTRING ret_val(4 * n_nibbles);
  unsigned char *bits_ptr = ret_val.val_ptr->bits_ptr;
  int n_octets = (n_nibbles + 1) / 2;
  for (int i = 0; i < n_octets; i++) {
    bits_ptr[i] = nibble_reverse_table[nibbles_ptr[i]];
  }
  ret_val.clear_unused_bits();
  return ret_val;
}

BITSTRING hex2bit(const HEXSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function hex2bit() is an unbound "
    "hexstring element.");
  unsigned char bits = nibble_reverse_table[value.get_nibble()];
  return BITSTRING(4, &bits);
}

// C.18 - hex2oct

OCTETSTRING hex2oct(const HEXSTRING& value)
{
  value.must_bound("The argument of function hex2oct() is an unbound "
    "hexstring value.");
  int n_nibbles = value.lengthof();
  int n_octets = (n_nibbles + 1) / 2;
  int padding_nibbles = n_nibbles % 2;
  const unsigned char *nibbles_ptr = (const unsigned char *)value;
  OCTETSTRING ret_val(n_octets);
  unsigned char *octets_ptr = ret_val.val_ptr->octets_ptr;
  if (padding_nibbles > 0) octets_ptr[0] = 0;
  for (int i = 0; i < n_nibbles; i++) {
    unsigned char hexdigit;
    if (i % 2) hexdigit = nibbles_ptr[i / 2] >> 4;
    else hexdigit = nibbles_ptr[i / 2] & 0x0F;
    if ((i + padding_nibbles) % 2)
      octets_ptr[(i + padding_nibbles) / 2] |= hexdigit;
    else octets_ptr[(i + padding_nibbles) / 2] = hexdigit << 4;
  }
  return ret_val;
}

OCTETSTRING hex2oct(const HEXSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function hex2oct() is an unbound "
    "hexstring element.");
  unsigned char octet = value.get_nibble();
  return OCTETSTRING(1, &octet);
}

// C.19 - hex2str

CHARSTRING hex2str(const HEXSTRING& value)
{
  value.must_bound("The argument of function hex2str() is an unbound "
    "hexstring value.");
  int n_nibbles = value.lengthof();
  const unsigned char *nibbles_ptr = (const unsigned char *)value;
  CHARSTRING ret_val(n_nibbles);
  char *chars_ptr = ret_val.val_ptr->chars_ptr;
  for (int i = 0; i < n_nibbles; i++) {
    unsigned char hexdigit;
    if (i % 2) hexdigit = nibbles_ptr[i / 2] >> 4;
    else hexdigit = nibbles_ptr[i / 2] & 0x0F;
    chars_ptr[i] = hexdigit_to_char(hexdigit);
  }
  return ret_val;
}

CHARSTRING hex2str(const HEXSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function hex2str() is an unbound "
    "hexstring element.");
  return CHARSTRING(hexdigit_to_char(value.get_nibble()));
}

// C.20 - oct2int

INTEGER oct2int(const OCTETSTRING& value)
{
  value.must_bound("The argument of function oct2int() is an unbound "
    "octetstring value.");
  int n_octets = value.lengthof();
  const unsigned char *octet_ptr = (const unsigned char *)value;
  int start_index;
  for (start_index = 0; start_index < n_octets; start_index++)
    if (octet_ptr[start_index]) break;
  int_val_t ret_val((RInt)0);
  for (int i = start_index; i < n_octets; i++) {
    ret_val <<= 8;
    ret_val += octet_ptr[i];
  }
  if (ret_val.is_native()) return INTEGER(ret_val.get_val());
  else return INTEGER(BN_dup(ret_val.get_val_openssl()));
}

INTEGER oct2int(const OCTETSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function oct2int() is an unbound "
    "octetstring element.");
  return INTEGER(value.get_octet());
}

// C.21 - oct2bit

BITSTRING oct2bit(const OCTETSTRING& value)
{
  value.must_bound("The argument of function oct2bit() is an unbound "
    "octetstring value.");
  int n_octets = value.lengthof();
  const unsigned char *octets_ptr = (const unsigned char *)value;
  BITSTRING ret_val(8 * n_octets);
  unsigned char *bits_ptr = ret_val.val_ptr->bits_ptr;
  for (int i = 0; i < n_octets; i++) {
    bits_ptr[i] = bit_reverse_table[octets_ptr[i]];
  }
  return ret_val;
}

BITSTRING oct2bit(const OCTETSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function oct2bit() is an unbound "
    "octetstring element.");
  unsigned char bits = bit_reverse_table[value.get_octet()];
  return BITSTRING(8, &bits);
}

// C.22 - oct2hex

HEXSTRING oct2hex(const OCTETSTRING& value)
{
  value.must_bound("The argument of function oct2hex() is an unbound "
    "octetstring value.");
  int n_octets = value.lengthof();
  const unsigned char *octets_ptr = (const unsigned char *)value;
  HEXSTRING ret_val(2 * n_octets);
  unsigned char *nibbles_ptr = ret_val.val_ptr->nibbles_ptr;
  for (int i = 0; i < n_octets; i++) {
    nibbles_ptr[i] = nibble_swap_table[octets_ptr[i]];
  }
  return ret_val;
}

HEXSTRING oct2hex(const OCTETSTRING_ELEMENT& value)
{
  value.must_bound("The argument of function oct2hex() is an unbound "
    "octetstring element.");
  unsigned char nibbles = nibble_swap_table[value.get_octet()];
  return HEXSTRING(2, &nibbles);
}

// C.23 - oct2str

CHARSTRING oct2str(const OCTETSTRING& value)
{
  value.must_bound("The argument of function oct2str() is an unbound "
    "octetstring value.");
  int n_octets = value.lengthof();
  const unsigned char *octets_ptr = (const unsigned char *)value;
  CHARSTRING ret_val(2 * n_octets);
For faster browsing, not all history is shown. View entire blame