1 /******************************************************************************
2 * Copyright (c) 2000-2016 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
13 ******************************************************************************/
20 #include "../common/memory.h"
22 // Note: Do not use dbgnew.hh. It doesn't play well with Qt in mctr_gui.
23 // This class is mostly the same as compiler2/Int.cc/Int.hh. They should be
24 // merged later, but it doesn't seem to be easy.
26 #include <openssl/crypto.h>
27 #include <openssl/bn.h>
29 int_val_t::int_val_t() : native_flag(true)
34 int_val_t::int_val_t(const int_val_t
& v
)
36 native_flag
= v
.is_native();
37 if (native_flag
) val
.native
= v
.get_val();
38 else val
.openssl
= BN_dup(v
.get_val_openssl());
41 int_val_t::int_val_t(const char *s
)
44 if (!BN_dec2bn(&n
, *s
== '+' ? s
+ 1 : s
))
45 TTCN_error("Unexpected error when converting `%s' to integer", s
);
46 if (BN_num_bits(n
) > (int)sizeof(int) * 8 - 1) {
51 val
.native
= string2RInt(s
);
56 int_val_t::~int_val_t()
58 if (!native_flag
) BN_free(val
.openssl
);
61 const RInt
& int_val_t::get_val() const
63 if (!native_flag
) TTCN_error("Invalid conversion of a large integer value");
67 BIGNUM
*int_val_t::get_val_openssl() const
69 if (native_flag
) TTCN_error("Invalid conversion of a large integer value");
73 // The returned string must be freed with Free by the caller. Returning
74 // CHARSTRING would be much better, but there're some linking issues.
75 char *int_val_t::as_string() const
78 char *tmp
= mprintf("%d", val
.native
);
81 char *tmp1
= NULL
, *tmp2
= NULL
;
82 if (!(tmp1
= BN_bn2dec(val
.openssl
))) TTCN_error("int_val_t::c_str()");
83 tmp2
= mcopystr(tmp1
);
89 int_val_t
& int_val_t::operator=(RInt v
)
91 if (!native_flag
) BN_free(val
.openssl
);
97 int_val_t
& int_val_t::operator=(const int_val_t
& right
)
99 if (!native_flag
) BN_free(val
.openssl
);
100 native_flag
= right
.is_native();
101 if (native_flag
) val
.native
= right
.get_val();
102 else val
.openssl
= BN_dup(right
.get_val_openssl());
106 int_val_t
& int_val_t::operator<<=(RInt right
)
108 // It makes no sense to support negative operands. GCC returns constant "0"
109 // with "warning: left shift count is negative" for these shifts.
110 if (right
< 0) TTCN_error("The second operand of bitwise shift operators "
111 "cannot be negative");
112 if (right
== 0) return *this;
114 BIGNUM
*result
= BN_new();
115 // Ugly, but can't do better now.
116 char *tmp_str
= as_string();
117 BN_dec2bn(&result
, tmp_str
);
119 BN_lshift(result
, result
, right
);
120 if (BN_num_bits(result
) > (int)sizeof(int) * 8 - 1) {
121 val
.openssl
= result
;
124 val
.native
<<= right
;
128 BN_lshift(val
.openssl
, val
.openssl
, right
);
133 int_val_t
& int_val_t::operator>>=(RInt right
)
135 if (right
< 0) TTCN_error("The second operand of bitwise shift operators "
136 "cannot be negative");
137 if (right
== 0) return *this;
139 val
.native
>>= right
;
141 BN_rshift(val
.openssl
, val
.openssl
, right
);
142 if (BN_num_bits(val
.openssl
) <= (int)sizeof(RInt
) * 8 - 1) {
143 char *result_str
= BN_bn2dec(val
.openssl
);
144 RInt result_i
= string2RInt(result_str
);
145 OPENSSL_free(result_str
);
147 BN_free(val
.openssl
);
148 val
.native
= result_i
;
154 int_val_t
& int_val_t::operator+=(RInt right
)
156 // Unfortunately we have to check the sign of the "right" operand and
157 // perform addition or subtraction accordingly.
158 if (right
== 0) return *this;
159 bool neg
= right
< 0;
161 BIGNUM
*result
= BN_new();
162 BN_set_word(result
, (BN_ULONG
)val
.native
);
163 if (neg
) BN_sub_word(result
, (BN_ULONG
)right
);
164 else BN_add_word(result
, (BN_ULONG
)right
);
165 if (BN_num_bits(result
) > (int)sizeof(int) * 8 - 1) {
166 val
.openssl
= result
;
173 if (neg
) BN_sub_word(val
.openssl
, (BN_ULONG
)right
);
174 else BN_add_word(val
.openssl
, (BN_ULONG
)right
);
175 if (BN_num_bits(val
.openssl
) <= (int)sizeof(int) * 8 - 1) {
176 BN_ULONG tmp
= BN_get_word(val
.openssl
);
177 if (BN_is_negative(val
.openssl
)) tmp
*= -1;
178 BN_free(val
.openssl
);
186 bool int_val_t::operator==(const int_val_t
& right
) const
189 if (right
.is_native()) {
190 return val
.native
== right
.val
.native
;
192 BIGNUM
*this_big
= to_openssl(val
.native
);
193 int eq
= BN_cmp(this_big
, right
.get_val_openssl());
198 if (right
.is_native()) {
199 BIGNUM
*right_big
= to_openssl(right
.val
.native
);
200 int eq
= BN_cmp(val
.openssl
, right_big
);
204 return BN_cmp(val
.openssl
, right
.val
.openssl
) == 0;
209 bool int_val_t::operator<(const int_val_t
& v
) const
213 return val
.native
< v
.val
.native
;
215 BIGNUM
*this_big
= to_openssl(val
.native
);
216 int this_equ
= BN_cmp(this_big
, v
.get_val_openssl());
218 return this_equ
== -1;
222 BIGNUM
*v_big
= to_openssl(v
.val
.native
);
223 int v_equ
= BN_cmp(val
.openssl
, v_big
);
227 return BN_cmp(val
.openssl
, v
.val
.openssl
) == -1;
232 int_val_t
int_val_t::operator&(RInt right
) const
234 // TODO Right can be int_val_t. BN_is_bit_set/BN_set_bit should be used.
235 BN_ULONG right_bn_ulong
= (BN_ULONG
)right
;
236 if (right
!= (RInt
)right_bn_ulong
) TTCN_error("Bitmask is too big");
238 return int_val_t(val
.native
& right
);
240 BIGNUM
*tmp
= BN_dup(val
.openssl
);
241 BN_mask_bits(tmp
, sizeof(BN_ULONG
) * 8);
242 BN_ULONG word
= BN_get_word(tmp
);
244 return int_val_t(word
& right_bn_ulong
);
248 // Cannot be inline since bignum_st is just a forward declaration in the
249 // header. The compiler must know bignum_st at this point.
250 bool int_val_t::is_negative() const
252 return (native_flag
&& val
.native
< 0) ||
253 (!native_flag
&& BN_is_negative(val
.openssl
));
256 double int_val_t::to_real() const
259 return (double)val
.native
;
261 char *result_str
= BN_bn2dec(val
.openssl
);
263 if (sscanf(result_str
, "%lf", &result
) != 1)
264 TTCN_error("Conversion of integer value `%s' to float failed",
266 OPENSSL_free(result_str
);
271 BIGNUM
*to_openssl(int other_value
)
273 BIGNUM
*result
= NULL
;
274 char *str
= mprintf("%d", other_value
);
275 BN_dec2bn(&result
, str
);
280 RInt
string2RInt(const char *s
)
283 RInt i
= (RInt
)strtol(s
, (char **)NULL
, 10);
286 TTCN_error("Overflow when converting `%s' to integer value: %s", s
,
291 default: // EINVAL and others.
292 TTCN_error("Unexpected error when converting `%s' to integer: %s", s
,
This page took 0.035399 seconds and 5 git commands to generate.