X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/5aff007d8fcfb4c6cc3c3627ae15f45562db7a0d..5d22a5aeb435e90f20e5f8fd77c2256fd21d5f92:/lib/basen.c diff --git a/lib/basen.c b/lib/basen.c index 74cb836..7c1f9ec 100644 --- a/lib/basen.c +++ b/lib/basen.c @@ -2,20 +2,18 @@ * This file is part of DisOrder. * Copyright (C) 2005, 2007, 2008 Richard Kettlewell * - * This program is free software; you can redistribute it and/or modify + * 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 of the License, or + * the Free Software Foundation, either version 3 of the License, 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. - * + * + * 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 + * along with this program. If not, see . */ /** @file lib/basen.c @brief Arbitrary base conversion * @@ -24,10 +22,7 @@ * words. The words themselves use the native byte order. */ -#include -#include "types.h" - -#include +#include "common.h" #include "basen.h" @@ -36,7 +31,7 @@ * @param nwords Length of bignum * @return !v */ -static int zero(const unsigned long *v, int nwords) { +static int zero(const uint32_t *v, int nwords) { int n; for(n = 0; n < nwords && !v[n]; ++n) @@ -52,7 +47,7 @@ static int zero(const unsigned long *v, int nwords) { * * The quotient is stored in @p v. */ -static unsigned divide(unsigned long *v, int nwords, unsigned long m) { +static unsigned divide(uint32_t *v, int nwords, unsigned long m) { unsigned long r = 0, a, b; int n; @@ -71,6 +66,31 @@ static unsigned divide(unsigned long *v, int nwords, unsigned long m) { return r; } +/** @brief Multiple v by m and add a + * @param v Pointer to bigendian bignum + * @param nwords Length of bignum + * @param m Value to multiply by + * @param a Value to add + * @return 0 on success, non-0 on overflow + * + * Does v = m * v + a. + */ +static int mla(uint32_t *v, int nwords, uint32_t m, uint32_t a) { + int n = nwords - 1; + uint32_t carry = a; + + while(n >= 0) { + const uint64_t p = (uint64_t)v[n] * m + carry; + carry = (uint32_t)(p >> 32); + v[n] = (uint32_t)p; + --n; + } + /* If there is still a carry then we overflowed */ + return !!carry; +} + +static const char basen_chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + /** @brief Convert v to a chosen base * @param v Pointer to bigendian bignum (modified!) * @param nwords Length of bignum @@ -80,26 +100,53 @@ static unsigned divide(unsigned long *v, int nwords, unsigned long m) { * @return 0 on success, -1 if the buffer is too small * * Converts @p v to a string in the given base using decimal digits, lower case - * letter sand upper case letters as digits. + * letters and upper case letters as digits. + * + * The inverse of nesab(). */ -int basen(unsigned long *v, +int basen(uint32_t *v, int nwords, char buffer[], size_t bufsize, unsigned base) { size_t i = bufsize; - static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; do { if(i <= 1) return -1; /* overflow */ - buffer[--i] = chars[divide(v, nwords, base)]; + buffer[--i] = basen_chars[divide(v, nwords, base)]; } while(!zero(v, nwords)); memmove(buffer, buffer + i, bufsize - i); buffer[bufsize - i] = 0; return 0; } +/** @brief Convert a string back to a large integer in an arbitrary base + * @param v Where to store result as a bigendian bignum + * @param nwords Space available in @p v + * @param s Input string + * @param base Number base (2..62) + * @return 0 on success, non-0 on overflow or invalid input + * + * The inverse of basen(). If the number is much smaller than the buffer then + * the first words will be 0. + */ +int nesab(uint32_t *v, + int nwords, + const char *s, + unsigned base) { + /* Initialize to 0 */ + memset(v, 0, nwords * sizeof *v); + while(*s) { + const char *dp = strchr(basen_chars, *s++); + if(!dp) + return -1; + if(mla(v, nwords, base, dp - basen_chars)) + return -1; + } + return 0; +} + /* Local Variables: c-basic-offset:2