Blame mpz/inp_raw.c

Packit 5c3484
/* mpz_inp_raw -- read an mpz_t in raw format.
Packit 5c3484
Packit 5c3484
Copyright 2001, 2002, 2005, 2012, 2016 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include <stdio.h>
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* NTOH_LIMB_FETCH fetches a limb which is in network byte order (ie. big
Packit 5c3484
   endian) and produces a normal host byte order result. */
Packit 5c3484
Packit 5c3484
#if HAVE_LIMB_BIG_ENDIAN
Packit 5c3484
#define NTOH_LIMB_FETCH(limb, src)  do { (limb) = *(src); } while (0)
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if HAVE_LIMB_LITTLE_ENDIAN
Packit 5c3484
#define NTOH_LIMB_FETCH(limb, src)  BSWAP_LIMB_FETCH (limb, src)
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#ifndef NTOH_LIMB_FETCH
Packit 5c3484
#define NTOH_LIMB_FETCH(limb, src)                              \
Packit 5c3484
  do {                                                          \
Packit 5c3484
    const unsigned char  *__p = (const unsigned char *) (src);  \
Packit 5c3484
    mp_limb_t  __limb;                                          \
Packit 5c3484
    int        __i;                                             \
Packit 5c3484
    __limb = 0;                                                 \
Packit 5c3484
    for (__i = 0; __i < GMP_LIMB_BYTES; __i++)               \
Packit 5c3484
      __limb = (__limb << 8) | __p[__i];                        \
Packit 5c3484
    (limb) = __limb;                                            \
Packit 5c3484
  } while (0)
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Enhancement: The byte swap loop ought to be safe to vectorize on Cray
Packit 5c3484
   etc, but someone who knows what they're doing needs to check it.  */
Packit 5c3484
Packit 5c3484
size_t
Packit 5c3484
mpz_inp_raw (mpz_ptr x, FILE *fp)
Packit 5c3484
{
Packit 5c3484
  unsigned char  csize_bytes[4];
Packit 5c3484
  mp_size_t      csize, abs_xsize, i;
Packit 5c3484
  size_t         size;
Packit 5c3484
  size_t         abs_csize;
Packit 5c3484
  char           *cp;
Packit 5c3484
  mp_ptr         xp, sp, ep;
Packit 5c3484
  mp_limb_t      slimb, elimb;
Packit 5c3484
Packit 5c3484
  if (fp == 0)
Packit 5c3484
    fp = stdin;
Packit 5c3484
Packit 5c3484
  /* 4 bytes for size */
Packit 5c3484
  if (fread (csize_bytes, sizeof (csize_bytes), 1, fp) != 1)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  size = (((size_t) csize_bytes[0] << 24) + ((size_t) csize_bytes[1] << 16) +
Packit 5c3484
	  ((size_t) csize_bytes[2] << 8)  + ((size_t) csize_bytes[3]));
Packit 5c3484
Packit 5c3484
  if (size < 0x80000000u)
Packit 5c3484
    csize = size;
Packit 5c3484
  else
Packit 5c3484
    csize = size - 0x80000000u - 0x80000000u;
Packit 5c3484
Packit 5c3484
  abs_csize = ABS (csize);
Packit 5c3484
Packit 5c3484
  /* round up to a multiple of limbs */
Packit 5c3484
  abs_xsize = BITS_TO_LIMBS (abs_csize*8);
Packit 5c3484
Packit 5c3484
  if (abs_xsize != 0)
Packit 5c3484
    {
Packit 5c3484
      xp = MPZ_NEWALLOC (x, abs_xsize);
Packit 5c3484
Packit 5c3484
      /* Get limb boundaries right in the read, for the benefit of the
Packit 5c3484
	 non-nails case.  */
Packit 5c3484
      xp[0] = 0;
Packit 5c3484
      cp = (char *) (xp + abs_xsize) - abs_csize;
Packit 5c3484
      if (fread (cp, abs_csize, 1, fp) != 1)
Packit 5c3484
	return 0;
Packit 5c3484
Packit 5c3484
      if (GMP_NAIL_BITS == 0)
Packit 5c3484
	{
Packit 5c3484
	  /* Reverse limbs to least significant first, and byte swap.  If
Packit 5c3484
	     abs_xsize is odd then on the last iteration elimb and slimb are
Packit 5c3484
	     the same.  It doesn't seem extra code to handle that case
Packit 5c3484
	     separately, to save an NTOH.  */
Packit 5c3484
	  sp = xp;
Packit 5c3484
	  ep = xp + abs_xsize-1;
Packit 5c3484
	  for (i = 0; i < (abs_xsize+1)/2; i++)
Packit 5c3484
	    {
Packit 5c3484
	      NTOH_LIMB_FETCH (elimb, ep);
Packit 5c3484
	      NTOH_LIMB_FETCH (slimb, sp);
Packit 5c3484
	      *sp++ = elimb;
Packit 5c3484
	      *ep-- = slimb;
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  /* It ought to be possible to do the transformation in-place, but
Packit 5c3484
	     for now it's easier to use an extra temporary area.  */
Packit 5c3484
	  mp_limb_t  byte, limb;
Packit 5c3484
	  int	     bits;
Packit 5c3484
	  mp_size_t  tpos;
Packit 5c3484
	  mp_ptr     tp;
Packit 5c3484
	  TMP_DECL;
Packit 5c3484
Packit 5c3484
	  TMP_MARK;
Packit 5c3484
	  tp = TMP_ALLOC_LIMBS (abs_xsize);
Packit 5c3484
	  limb = 0;
Packit 5c3484
	  bits = 0;
Packit 5c3484
	  tpos = 0;
Packit 5c3484
	  for (i = abs_csize-1; i >= 0; i--)
Packit 5c3484
	    {
Packit 5c3484
	      byte = (unsigned char) cp[i];
Packit 5c3484
	      limb |= (byte << bits);
Packit 5c3484
	      bits += 8;
Packit 5c3484
	      if (bits >= GMP_NUMB_BITS)
Packit 5c3484
		{
Packit 5c3484
		  ASSERT (tpos < abs_xsize);
Packit 5c3484
		  tp[tpos++] = limb & GMP_NUMB_MASK;
Packit 5c3484
		  bits -= GMP_NUMB_BITS;
Packit 5c3484
		  ASSERT (bits < 8);
Packit 5c3484
		  limb = byte >> (8 - bits);
Packit 5c3484
		}
Packit 5c3484
	    }
Packit 5c3484
	  if (bits != 0)
Packit 5c3484
	    {
Packit 5c3484
	      ASSERT (tpos < abs_xsize);
Packit 5c3484
	      tp[tpos++] = limb;
Packit 5c3484
	    }
Packit 5c3484
	  ASSERT (tpos == abs_xsize);
Packit 5c3484
Packit 5c3484
	  MPN_COPY (xp, tp, abs_xsize);
Packit 5c3484
	  TMP_FREE;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      /* GMP 1.x mpz_out_raw wrote high zero bytes, strip any high zero
Packit 5c3484
	 limbs resulting from this.  Should be a non-zero value here, but
Packit 5c3484
	 for safety don't assume that. */
Packit 5c3484
      MPN_NORMALIZE (xp, abs_xsize);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  SIZ(x) = (csize >= 0 ? abs_xsize : -abs_xsize);
Packit 5c3484
  return abs_csize + 4;
Packit 5c3484
}