#include "platform.h" #include "mp.h" #define between(x,min,max) (((min-1-x) & (x-max-1))>>8) static int dec32chr(int c) { int o; o = between(c, 'A', 'Z') & (1+(c-'A')); o |= between(c, 'a', 'z') & (1+(c-'a')); o |= between(c, '2', '7') & (1+26+(c-'2')); return o-1; } static int dec32x(u8int *dest, int ndest, const char *src, int nsrc, int (*chr)(int)) { u8int *start; int i, j, u[8]; if(ndest+1 < (5*nsrc+7)/8) return -1; start = dest; while(nsrc>=8){ for(i=0; i<8; i++){ j = chr(src[i]); if(j < 0) j = 0; u[i] = j; } *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2)); *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); *dest++ = ((0x7 & u[6])<<5) | u[7]; src += 8; nsrc -= 8; } if(nsrc > 0){ if(nsrc == 1 || nsrc == 3 || nsrc == 6) return -1; for(i=0; i>2)); if(nsrc == 2) goto out; *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); if(nsrc == 4) goto out; *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); if(nsrc == 5) goto out; *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); } out: return dest-start; } int dec32(u8int *dest, int ndest, const char *src, int nsrc) { return dec32x(dest, ndest, src, nsrc, dec32chr); } static const char * frompow2(const char *a, mpint *b, int s) { const char *p, *next; mpdigit x; u32int i; i = 1<top = 0; next = p; while(p > a){ x = 0; for(i = 0; i < Dbits; i += s){ if(p <= a) break; x |= dec16chr(*--p)<p[b->top++] = x; } return next; } static const char* from8(const char *a, mpint *b) { const char *p, *next; mpdigit x, y; int i; for(p = a; ((*p - '0') & 255) < 8; p++) ; mpbits(b, (p-a)*3); b->top = 0; next = p; i = 0; x = y = 0; while(p > a){ y = *--p - '0'; x |= y << i; i += 3; if(i >= Dbits){ Digout: i -= Dbits; b->p[b->top++] = x; if(i <= -(64-3)) x = 0; else x = y >> (3-i); } } if(i > 0) goto Digout; return next; } static u32int mppow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; static const char* from10(const char *a, mpint *b) { u32int x, y; mpint *pow, *r; int i; pow = mpnew(0); r = mpnew(0); b->top = 0; for(;;){ // do a billion at a time in native arithmetic x = 0; for(i = 0; i < 9; i++){ y = *a - '0'; if(y > 9) break; a++; x *= 10; x += y; } if(i == 0) break; // accumulate into mpint uitomp(mppow10[i], pow); uitomp(x, r); mpmul(b, pow, b); mpadd(b, r, b); if(i < 9) break; } mpfree(pow); mpfree(r); return a; } static const char* fromdecx(const char *a, mpint *b, int (*chr)(int), int (*dec)(u8int*, int, const char*, int)) { const char *buf = a; u8int *p; int n, m; b->top = 0; for(; chr(*a) >= 0; a++) ; n = a-buf; if(n > 0){ p = MEM_ALLOC(n); if(p == nil) abort(); m = dec(p, n, buf, n); if(m > 0) betomp(p, m, b); MEM_FREE(p); } return a; } mpint* strtomp(const char *a, char **pp, int base, mpint *b) { int sign; const char *e; if(b == nil) b = mpnew(0); while(*a==' ' || *a=='\t') a++; sign = 1; for(;; a++){ switch(*a){ case '-': sign *= -1; continue; } break; } if(base == 0){ base = 10; if(a[0] == '0'){ if(a[1] == 'x' || a[1] == 'X'){ a += 2; base = 16; }else if(a[1] == 'b' || a[1] == 'B'){ a += 2; base = 2; }else if(a[1] >= '0' && a[1] <= '7'){ a++; base = 8; } } } switch(base){ case 2: e = frompow2(a, b, 1); break; case 4: e = frompow2(a, b, 2); break; case 8: e = from8(a, b); break; case 10: e = from10(a, b); break; case 16: e = frompow2(a, b, 4); break; case 32: e = fromdecx(a, b, dec32chr, dec32); break; default: abort(); return nil; } if(pp != nil) *pp = (char*)e; // if no characters parsed, there wasn't a number to convert if(e == a) return nil; b->sign = sign; return mpnorm(b); }