diff options
Diffstat (limited to 'src/mp-binary.c')
-rw-r--r-- | src/mp-binary.c | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/src/mp-binary.c b/src/mp-binary.c new file mode 100644 index 0000000..e4cedba --- /dev/null +++ b/src/mp-binary.c @@ -0,0 +1,208 @@ +/* Copyright (c) 1987-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2008-2009 Robert Ancell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <stdio.h> + +#include "mp.h" +#include "mp-private.h" + +// FIXME: Make dynamic +#define MAX_DIGITS 1000 + +static char digits[] = "0123456789ABCDEF"; + +static int hex_to_int(char digit) +{ + if (digit >= '0' && digit <= '9') + return digit - '0'; + if (digit >= 'A' && digit <= 'F') + return digit - 'A' + 10; + if (digit >= 'a' && digit <= 'f') + return digit - 'a' + 10; + return 0; +} + + +static void +mp_bitwise(const MPNumber *x, const MPNumber *y, int (*bitwise_operator)(int, int), MPNumber *z, int wordlen) +{ + char text1[MAX_DIGITS], text2[MAX_DIGITS], text_out[MAX_DIGITS], text_out2[MAX_DIGITS]; + int offset1, offset2, offset_out; + + mp_cast_to_string(x, 16, 16, 0, 0, text1, MAX_DIGITS); + mp_cast_to_string(y, 16, 16, 0, 0, text2, MAX_DIGITS); + offset1 = strlen(text1) - 1; + offset2 = strlen(text2) - 1; + offset_out = wordlen / 4 - 1; + if (offset_out <= 0) { + offset_out = offset1 > offset2 ? offset1 : offset2; + } + if (offset_out > 0 && (offset_out < offset1 || offset_out < offset2)) { + mperr("Overflow. Try a bigger word size"); + return; + } + + /* Perform bitwise operator on each character from right to left */ + for (text_out[offset_out+1] = '\0'; offset_out >= 0; offset_out--) { + int v1 = 0, v2 = 0; + + if (offset1 >= 0) { + v1 = hex_to_int(text1[offset1]); + offset1--; + } + if (offset2 >= 0) { + v2 = hex_to_int(text2[offset2]); + offset2--; + } + text_out[offset_out] = digits[bitwise_operator(v1, v2)]; + } + + snprintf(text_out2, MAX_DIGITS, "%s", text_out); + mp_set_from_string(text_out2, 16, z); +} + + +static int mp_bitwise_and(int v1, int v2) { return v1 & v2; } +static int mp_bitwise_or(int v1, int v2) { return v1 | v2; } +static int mp_bitwise_xor(int v1, int v2) { return v1 ^ v2; } +static int mp_bitwise_not(int v1, int dummy) { return v1 ^ 0xF; } + + +bool +mp_is_overflow (const MPNumber *x, int wordlen) +{ + MPNumber tmp1, tmp2; + mp_set_from_integer(2, &tmp1); + mp_xpowy_integer(&tmp1, wordlen, &tmp2); + return mp_is_greater_than (&tmp2, x); +} + + +void +mp_and(const MPNumber *x, const MPNumber *y, MPNumber *z) +{ + if (!mp_is_positive_integer(x) || !mp_is_positive_integer(y)) + { + /* Translators: Error displayed when boolean AND attempted on non-integer values */ + mperr(_("Boolean AND is only defined for positive integers")); + } + + mp_bitwise(x, y, mp_bitwise_and, z, 0); +} + + +void +mp_or(const MPNumber *x, const MPNumber *y, MPNumber *z) +{ + if (!mp_is_positive_integer(x) || !mp_is_positive_integer(y)) + { + /* Translators: Error displayed when boolean OR attempted on non-integer values */ + mperr(_("Boolean OR is only defined for positive integers")); + } + + mp_bitwise(x, y, mp_bitwise_or, z, 0); +} + + +void +mp_xor(const MPNumber *x, const MPNumber *y, MPNumber *z) +{ + if (!mp_is_positive_integer(x) || !mp_is_positive_integer(y)) + { + /* Translators: Error displayed when boolean XOR attempted on non-integer values */ + mperr(_("Boolean XOR is only defined for positive integers")); + } + + mp_bitwise(x, y, mp_bitwise_xor, z, 0); +} + + +void +mp_not(const MPNumber *x, int wordlen, MPNumber *z) +{ + MPNumber temp; + + if (!mp_is_positive_integer(x)) + { + /* Translators: Error displayed when boolean XOR attempted on non-integer values */ + mperr(_("Boolean NOT is only defined for positive integers")); + } + + mp_set_from_integer(0, &temp); + mp_bitwise(x, &temp, mp_bitwise_not, z, wordlen); +} + + +void +mp_mask(const MPNumber *x, int wordlen, MPNumber *z) +{ + char text[MAX_DIGITS]; + size_t len, offset; + + /* Convert to a hexadecimal string and use last characters */ + mp_cast_to_string(x, 16, 16, 0, 0, text, MAX_DIGITS); + len = strlen(text); + offset = wordlen / 4; + offset = len > offset ? len - offset: 0; + mp_set_from_string(text + offset, 16, z); +} + + +void +mp_shift(const MPNumber *x, int count, MPNumber *z) +{ + int i, multiplier = 1; + + if (!mp_is_integer(x)) { + /* Translators: Error displayed when bit shift attempted on non-integer values */ + mperr(_("Shift is only possible on integer values")); + return; + } + + if (count >= 0) { + for (i = 0; i < count; i++) + multiplier *= 2; + mp_multiply_integer(x, multiplier, z); + } + else { + MPNumber temp; + for (i = 0; i < -count; i++) + multiplier *= 2; + mp_divide_integer(x, multiplier, &temp); + mp_floor(&temp, z); + } +} + + +void +mp_ones_complement(const MPNumber *x, int wordlen, MPNumber *z) +{ + MPNumber t; + mp_set_from_integer(0, &t); + mp_bitwise(x, &t, mp_bitwise_xor, z, wordlen); + mp_not(z, wordlen, z); +} + + +void +mp_twos_complement(const MPNumber *x, int wordlen, MPNumber *z) +{ + mp_ones_complement (x, wordlen, z); + mp_add_integer (z, 1, z); +} |