github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpz/import.c (about)

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