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