/* mpz_out_raw -- write an mpz_t in raw format. Copyright 2001, 2002 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The GNU MP Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ #include #include "gmp.h" #include "gmp-impl.h" #include "longlong.h" /* HTON_LIMB_STORE takes a normal host byte order limb and stores it as network byte order (ie. big endian). */ #if HAVE_LIMB_BIG_ENDIAN #define HTON_LIMB_STORE(dst, limb) do { *(dst) = (limb); } while (0) #endif #if HAVE_LIMB_LITTLE_ENDIAN #define HTON_LIMB_STORE(dst, limb) BSWAP_LIMB_STORE (dst, limb) #endif #ifndef HTON_LIMB_STORE #define HTON_LIMB_STORE(dst, limb) \ do { \ mp_limb_t __limb = (limb); \ char *__p = (char *) (dst); \ int __i; \ for (__i = 0; __i < BYTES_PER_MP_LIMB; __i++) \ __p[__i] = (char) (__limb >> ((BYTES_PER_MP_LIMB-1 - __i) * 8)); \ } while (0) #endif size_t mpz_out_raw (FILE *fp, mpz_srcptr x) { mp_size_t xsize, abs_xsize, bytes, i; mp_srcptr xp; char *tp, *bp; mp_limb_t xlimb; int zeros; size_t tsize, ssize; xsize = SIZ(x); abs_xsize = ABS (xsize); bytes = (abs_xsize * GMP_NUMB_BITS + 7) / 8; tsize = ROUND_UP_MULTIPLE ((unsigned) 4, BYTES_PER_MP_LIMB) + bytes; tp = __GMP_ALLOCATE_FUNC_TYPE (tsize, char); bp = tp + ROUND_UP_MULTIPLE ((unsigned) 4, BYTES_PER_MP_LIMB); if (bytes != 0) { bp += bytes; xp = PTR (x); i = abs_xsize; if (GMP_NAIL_BITS == 0) { /* reverse limb order, and byte swap if necessary */ #ifdef _CRAY _Pragma ("_CRI ivdep"); #endif do { bp -= BYTES_PER_MP_LIMB; xlimb = *xp; HTON_LIMB_STORE ((mp_ptr) bp, xlimb); xp++; } while (--i > 0); /* strip high zero bytes (without fetching from bp) */ count_leading_zeros (zeros, xlimb); zeros /= 8; bp += zeros; bytes -= zeros; } else { mp_limb_t new_xlimb; int bits; ASSERT_CODE (char *bp_orig = bp - bytes); ASSERT_ALWAYS (GMP_NUMB_BITS >= 8); bits = 0; xlimb = 0; for (;;) { while (bits >= 8) { ASSERT (bp > bp_orig); *--bp = xlimb & 0xFF; xlimb >>= 8; bits -= 8; } if (i == 0) break; new_xlimb = *xp++; i--; ASSERT (bp > bp_orig); *--bp = (xlimb | (new_xlimb << bits)) & 0xFF; xlimb = new_xlimb >> (8 - bits); bits += GMP_NUMB_BITS - 8; } if (bits != 0) { ASSERT (bp > bp_orig); *--bp = xlimb; } ASSERT (bp == bp_orig); while (*bp == 0) { bp++; bytes--; } } } /* total bytes to be written */ ssize = 4 + bytes; /* twos complement negative for the size value */ bytes = (xsize >= 0 ? bytes : -bytes); /* so we don't rely on sign extension in ">>" */ ASSERT_ALWAYS (sizeof (bytes) >= 4); bp[-4] = bytes >> 24; bp[-3] = bytes >> 16; bp[-2] = bytes >> 8; bp[-1] = bytes; bp -= 4; if (fp == 0) fp = stdout; if (fwrite (bp, ssize, 1, fp) != 1) ssize = 0; (*__gmp_free_func) (tp, tsize); return ssize; }