(root)/
gmp-6.3.0/
mpz/
import.c
       1  /* mpz_import -- set mpz from word data.
       2  
       3  Copyright 2002, 2012, 2021, 2022 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  
      36  #if HAVE_LIMB_BIG_ENDIAN
      37  #define HOST_ENDIAN     1
      38  #endif
      39  #if HAVE_LIMB_LITTLE_ENDIAN
      40  #define HOST_ENDIAN     (-1)
      41  #endif
      42  #ifndef HOST_ENDIAN
      43  static const mp_limb_t  endian_test = (CNST_LIMB(1) << (GMP_LIMB_BITS-7)) - 1;
      44  #define HOST_ENDIAN     (* (signed char *) &endian_test)
      45  #endif
      46  
      47  
      48  void
      49  mpz_import (mpz_ptr z, size_t count, int order,
      50  	    size_t size, int endian, size_t nail, const void *data)
      51  {
      52    mp_size_t  zsize;
      53    mp_ptr     zp;
      54  
      55    ASSERT (order == 1 || order == -1);
      56    ASSERT (endian == 1 || endian == 0 || endian == -1);
      57    ASSERT (nail <= 8*size);
      58  
      59    zsize = BITS_TO_LIMBS (count * (8*size - nail));
      60    zp = MPZ_NEWALLOC (z, zsize);
      61  
      62    if (endian == 0)
      63      endian = HOST_ENDIAN;
      64  
      65    /* Can't use these special cases with nails currently, since they don't
      66       mask out the nail bits in the input data.  */
      67    if (nail == 0 && GMP_NAIL_BITS == 0
      68        && size == sizeof (mp_limb_t)
      69        && (((char *) data - (char *) NULL) % sizeof (mp_limb_t)) == 0 /* align */)
      70      {
      71        if (order == -1)
      72  	{
      73  	  if (endian == HOST_ENDIAN)
      74  	    MPN_COPY (zp, (mp_srcptr) data, (mp_size_t) count);
      75  	  else /* if (endian == - HOST_ENDIAN) */
      76  	    MPN_BSWAP (zp, (mp_srcptr) data, (mp_size_t) count);
      77  	}
      78        else /* if (order == 1) */
      79  	{
      80  	  if (endian == HOST_ENDIAN)
      81  	    MPN_REVERSE (zp, (mp_srcptr) data, (mp_size_t) count);
      82  	  else /* if (endian == - HOST_ENDIAN) */
      83  	    MPN_BSWAP_REVERSE (zp, (mp_srcptr) data, (mp_size_t) count);
      84  	}
      85      }
      86    else
      87    {
      88      mp_limb_t      limb, byte, wbitsmask;
      89      size_t         i, j, numb, wbytes;
      90      mp_size_t      woffset;
      91      unsigned char  *dp;
      92      int            lbits, wbits;
      93  
      94      numb = size * 8 - nail;
      95  
      96      /* whole bytes to process */
      97      wbytes = numb / 8;
      98  
      99      /* partial byte to process */
     100      wbits = numb % 8;
     101      wbitsmask = (CNST_LIMB(1) << wbits) - 1;
     102  
     103      /* offset to get to the next word after processing wbytes and wbits */
     104      woffset = (numb + 7) / 8;
     105      woffset = (endian >= 0 ? woffset : -woffset)
     106        + (order < 0 ? size : - (mp_size_t) size);
     107  
     108      /* least significant byte */
     109      dp = (unsigned char *) data
     110        + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0);
     111  
     112  #define ACCUMULATE(N)                                   \
     113      do {                                                \
     114        ASSERT (lbits < GMP_NUMB_BITS);                   \
     115        ASSERT (limb <= (CNST_LIMB(1) << lbits) - 1);     \
     116                                                          \
     117        limb |= (mp_limb_t) byte << lbits;                \
     118        lbits += (N);                                     \
     119        if (lbits >= GMP_NUMB_BITS)                       \
     120          {                                               \
     121            *zp++ = limb & GMP_NUMB_MASK;                 \
     122            lbits -= GMP_NUMB_BITS;                       \
     123            ASSERT (lbits < (N));                         \
     124            limb = byte >> ((N) - lbits);                 \
     125          }                                               \
     126      } while (0)
     127  
     128      limb = 0;
     129      lbits = 0;
     130      for (i = 0; i < count; i++)
     131        {
     132  	for (j = 0; j < wbytes; j++)
     133  	  {
     134  	    byte = *dp;
     135  	    dp -= endian;
     136  	    ACCUMULATE (8);
     137  	  }
     138  	if (wbits != 0)
     139  	  {
     140  	    byte = *dp & wbitsmask;
     141  	    dp -= endian;
     142  	    ACCUMULATE (wbits);
     143  	  }
     144  	dp += woffset;
     145        }
     146  
     147      if (lbits != 0)
     148        {
     149  	ASSERT (lbits <= GMP_NUMB_BITS);
     150  	ASSERT_LIMB (limb);
     151  	*zp++ = limb;
     152        }
     153  
     154      ASSERT (zp == PTR(z) + zsize);
     155  
     156      /* low byte of word after most significant */
     157      ASSERT (dp == (unsigned char *) data
     158  	    + (order < 0 ? count*size : - (mp_size_t) size)
     159  	    + (endian >= 0 ? (mp_size_t) size - 1 : 0));
     160  
     161    }
     162  
     163    zp = PTR(z);
     164    MPN_NORMALIZE (zp, zsize);
     165    SIZ(z) = zsize;
     166  }