1/* mpz_inp_raw -- read an mpz_t in raw format. 2 3Copyright 2001, 2002, 2005 Free Software Foundation, Inc. 4 5This file is part of the GNU MP Library. 6 7The GNU MP Library is free software; you can redistribute it and/or modify 8it under the terms of the GNU Lesser General Public License as published by 9the Free Software Foundation; either version 3 of the License, or (at your 10option) any later version. 11 12The GNU MP Library is distributed in the hope that it will be useful, but 13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15License for more details. 16 17You should have received a copy of the GNU Lesser General Public License 18along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ 19 20#include <stdio.h> 21#include "gmp.h" 22#include "gmp-impl.h" 23 24 25/* NTOH_LIMB_FETCH fetches a limb which is in network byte order (ie. big 26 endian) and produces a normal host byte order result. */ 27 28#if HAVE_LIMB_BIG_ENDIAN 29#define NTOH_LIMB_FETCH(limb, src) do { (limb) = *(src); } while (0) 30#endif 31 32#if HAVE_LIMB_LITTLE_ENDIAN 33#define NTOH_LIMB_FETCH(limb, src) BSWAP_LIMB_FETCH (limb, src) 34#endif 35 36#ifndef NTOH_LIMB_FETCH 37#define NTOH_LIMB_FETCH(limb, src) \ 38 do { \ 39 const unsigned char *__p = (const unsigned char *) (src); \ 40 mp_limb_t __limb; \ 41 int __i; \ 42 __limb = 0; \ 43 for (__i = 0; __i < BYTES_PER_MP_LIMB; __i++) \ 44 __limb = (__limb << 8) | __p[__i]; \ 45 (limb) = __limb; \ 46 } while (0) 47#endif 48 49 50/* Enhancement: The byte swap loop ought to be safe to vectorize on Cray 51 etc, but someone who knows what they're doing needs to check it. */ 52 53size_t 54mpz_inp_raw (mpz_ptr x, FILE *fp) 55{ 56 unsigned char csize_bytes[4]; 57 mp_size_t csize, abs_xsize, i; 58 size_t abs_csize; 59 char *cp; 60 mp_ptr xp, sp, ep; 61 mp_limb_t slimb, elimb; 62 63 if (fp == 0) 64 fp = stdin; 65 66 /* 4 bytes for size */ 67 if (fread (csize_bytes, sizeof (csize_bytes), 1, fp) != 1) 68 return 0; 69 70 csize = 71 ( (mp_size_t) csize_bytes[0] << 24) 72 + ((mp_size_t) csize_bytes[1] << 16) 73 + ((mp_size_t) csize_bytes[2] << 8) 74 + ((mp_size_t) csize_bytes[3]); 75 76 /* Sign extend if necessary. 77 Could write "csize -= ((csize & 0x80000000L) << 1)", but that tickles a 78 bug in gcc 3.0 for powerpc64 on AIX. */ 79 if (sizeof (csize) > 4 && csize & 0x80000000L) 80 csize -= 0x80000000L << 1; 81 82 abs_csize = ABS (csize); 83 84 /* round up to a multiple of limbs */ 85 abs_xsize = (abs_csize*8 + GMP_NUMB_BITS-1) / GMP_NUMB_BITS; 86 87 if (abs_xsize != 0) 88 { 89 MPZ_REALLOC (x, abs_xsize); 90 xp = PTR(x); 91 92 /* Get limb boundaries right in the read, for the benefit of the 93 non-nails case. */ 94 xp[0] = 0; 95 cp = (char *) (xp + abs_xsize) - abs_csize; 96 if (fread (cp, abs_csize, 1, fp) != 1) 97 return 0; 98 99 if (GMP_NAIL_BITS == 0) 100 { 101 /* Reverse limbs to least significant first, and byte swap. If 102 abs_xsize is odd then on the last iteration elimb and slimb are 103 the same. It doesn't seem extra code to handle that case 104 separately, to save an NTOH. */ 105 sp = xp; 106 ep = xp + abs_xsize-1; 107 for (i = 0; i < (abs_xsize+1)/2; i++) 108 { 109 NTOH_LIMB_FETCH (elimb, ep); 110 NTOH_LIMB_FETCH (slimb, sp); 111 *sp++ = elimb; 112 *ep-- = slimb; 113 } 114 } 115 else 116 { 117 /* It ought to be possible to do the transformation in-place, but 118 for now it's easier to use an extra temporary area. */ 119 mp_limb_t byte, limb; 120 int bits; 121 mp_size_t tpos; 122 mp_ptr tp; 123 TMP_DECL; 124 125 TMP_MARK; 126 tp = TMP_ALLOC_LIMBS (abs_xsize); 127 limb = 0; 128 bits = 0; 129 tpos = 0; 130 for (i = abs_csize-1; i >= 0; i--) 131 { 132 byte = (unsigned char) cp[i]; 133 limb |= (byte << bits); 134 bits += 8; 135 if (bits >= GMP_NUMB_BITS) 136 { 137 ASSERT (tpos < abs_xsize); 138 tp[tpos++] = limb & GMP_NUMB_MASK; 139 bits -= GMP_NUMB_BITS; 140 ASSERT (bits < 8); 141 limb = byte >> (8 - bits); 142 } 143 } 144 if (bits != 0) 145 { 146 ASSERT (tpos < abs_xsize); 147 tp[tpos++] = limb; 148 } 149 ASSERT (tpos == abs_xsize); 150 151 MPN_COPY (xp, tp, abs_xsize); 152 TMP_FREE; 153 } 154 155 /* GMP 1.x mpz_out_raw wrote high zero bytes, strip any high zero 156 limbs resulting from this. Should be a non-zero value here, but 157 for safety don't assume that. */ 158 MPN_NORMALIZE (xp, abs_xsize); 159 } 160 161 SIZ(x) = (csize >= 0 ? abs_xsize : -abs_xsize); 162 return abs_csize + 4; 163} 164