Fix crash doing bitwise operations with large numbers (Bug #637328)
[gcalctool.git] / src / mp-binary.c
blobd3c77c758afa9e91405019ab4b6a71ae1206d269
1 /* Copyright (c) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
2 * Copyright (c) 2008-2009 Robert Ancell
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include <stdio.h>
22 #include "mp.h"
23 #include "mp-private.h"
24 #include "mp-serializer.h"
26 // FIXME: Make dynamic
27 #define MAX_DIGITS 1000
29 static char digits[] = "0123456789ABCDEF";
31 static int hex_to_int(char digit)
33 if (digit >= '0' && digit <= '9')
34 return digit - '0';
35 if (digit >= 'A' && digit <= 'F')
36 return digit - 'A' + 10;
37 if (digit >= 'a' && digit <= 'f')
38 return digit - 'a' + 10;
39 return 0;
43 static gchar *
44 to_hex_string(const MPNumber *x)
46 MpSerializer *serializer;
47 gchar *result;
49 serializer = mp_serializer_new(MP_DISPLAY_FORMAT_FIXED, 16, 0);
50 result = mp_serializer_to_string(serializer, x);
51 g_object_unref(serializer);
53 return result;
57 static void
58 mp_bitwise(const MPNumber *x, const MPNumber *y, int (*bitwise_operator)(int, int), MPNumber *z, int wordlen)
60 char *text1, *text2, text_out[MAX_DIGITS], text_out2[MAX_DIGITS];
61 int offset1, offset2, offset_out;
63 text1 = to_hex_string(x);
64 text2 = to_hex_string(y);
65 offset1 = strlen(text1) - 1;
66 offset2 = strlen(text2) - 1;
67 offset_out = wordlen / 4 - 1;
68 if (offset_out <= 0) {
69 offset_out = offset1 > offset2 ? offset1 : offset2;
71 if (offset_out > 0 && (offset_out < offset1 || offset_out < offset2)) {
72 g_free(text1);
73 g_free(text2);
74 mp_set_from_integer(0, z);
75 mperr("Overflow. Try a bigger word size");
76 return;
79 /* Perform bitwise operator on each character from right to left */
80 for (text_out[offset_out+1] = '\0'; offset_out >= 0; offset_out--) {
81 int v1 = 0, v2 = 0;
83 if (offset1 >= 0) {
84 v1 = hex_to_int(text1[offset1]);
85 offset1--;
87 if (offset2 >= 0) {
88 v2 = hex_to_int(text2[offset2]);
89 offset2--;
91 text_out[offset_out] = digits[bitwise_operator(v1, v2)];
94 snprintf(text_out2, MAX_DIGITS, "%s", text_out);
95 mp_set_from_string(text_out2, 16, z);
96 g_free(text1);
97 g_free(text2);
101 static int mp_bitwise_and(int v1, int v2) { return v1 & v2; }
102 static int mp_bitwise_or(int v1, int v2) { return v1 | v2; }
103 static int mp_bitwise_xor(int v1, int v2) { return v1 ^ v2; }
104 static int mp_bitwise_not(int v1, int dummy) { return v1 ^ 0xF; }
107 bool
108 mp_is_overflow (const MPNumber *x, int wordlen)
110 MPNumber tmp1, tmp2;
111 mp_set_from_integer(2, &tmp1);
112 mp_xpowy_integer(&tmp1, wordlen, &tmp2);
113 return mp_is_greater_than (&tmp2, x);
117 void
118 mp_and(const MPNumber *x, const MPNumber *y, MPNumber *z)
120 if (!mp_is_positive_integer(x) || !mp_is_positive_integer(y))
122 /* Translators: Error displayed when boolean AND attempted on non-integer values */
123 mperr(_("Boolean AND is only defined for positive integers"));
126 mp_bitwise(x, y, mp_bitwise_and, z, 0);
130 void
131 mp_or(const MPNumber *x, const MPNumber *y, MPNumber *z)
133 if (!mp_is_positive_integer(x) || !mp_is_positive_integer(y))
135 /* Translators: Error displayed when boolean OR attempted on non-integer values */
136 mperr(_("Boolean OR is only defined for positive integers"));
139 mp_bitwise(x, y, mp_bitwise_or, z, 0);
143 void
144 mp_xor(const MPNumber *x, const MPNumber *y, MPNumber *z)
146 if (!mp_is_positive_integer(x) || !mp_is_positive_integer(y))
148 /* Translators: Error displayed when boolean XOR attempted on non-integer values */
149 mperr(_("Boolean XOR is only defined for positive integers"));
152 mp_bitwise(x, y, mp_bitwise_xor, z, 0);
156 void
157 mp_not(const MPNumber *x, int wordlen, MPNumber *z)
159 MPNumber temp;
161 if (!mp_is_positive_integer(x))
163 /* Translators: Error displayed when boolean XOR attempted on non-integer values */
164 mperr(_("Boolean NOT is only defined for positive integers"));
167 mp_set_from_integer(0, &temp);
168 mp_bitwise(x, &temp, mp_bitwise_not, z, wordlen);
172 void
173 mp_mask(const MPNumber *x, int wordlen, MPNumber *z)
175 char *text;
176 size_t len, offset;
178 /* Convert to a hexadecimal string and use last characters */
179 text = to_hex_string(x);
180 len = strlen(text);
181 offset = wordlen / 4;
182 offset = len > offset ? len - offset: 0;
183 mp_set_from_string(text + offset, 16, z);
184 g_free(text);
188 void
189 mp_shift(const MPNumber *x, int count, MPNumber *z)
191 int i, multiplier = 1;
193 if (!mp_is_integer(x)) {
194 /* Translators: Error displayed when bit shift attempted on non-integer values */
195 mperr(_("Shift is only possible on integer values"));
196 return;
199 if (count >= 0) {
200 for (i = 0; i < count; i++)
201 multiplier *= 2;
202 mp_multiply_integer(x, multiplier, z);
204 else {
205 MPNumber temp;
206 for (i = 0; i < -count; i++)
207 multiplier *= 2;
208 mp_divide_integer(x, multiplier, &temp);
209 mp_floor(&temp, z);
214 void
215 mp_ones_complement(const MPNumber *x, int wordlen, MPNumber *z)
217 MPNumber t;
218 mp_set_from_integer(0, &t);
219 mp_bitwise(x, &t, mp_bitwise_xor, z, wordlen);
220 mp_not(z, wordlen, z);
224 void
225 mp_twos_complement(const MPNumber *x, int wordlen, MPNumber *z)
227 mp_ones_complement (x, wordlen, z);
228 mp_add_integer (z, 1, z);