Home | History | Annotate | Line # | Download | only in mpz
      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-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     {
     69       unsigned  align = ((char *) data - (char *) NULL) % sizeof (mp_limb_t);
     70 
     71       if (order == -1
     72 	  && size == sizeof (mp_limb_t)
     73 	  && endian == HOST_ENDIAN
     74 	  && align == 0)
     75 	{
     76 	  MPN_COPY (zp, (mp_srcptr) data, (mp_size_t) count);
     77 	  goto done;
     78 	}
     79 
     80       if (order == -1
     81 	  && size == sizeof (mp_limb_t)
     82 	  && endian == - HOST_ENDIAN
     83 	  && align == 0)
     84 	{
     85 	  MPN_BSWAP (zp, (mp_srcptr) data, (mp_size_t) count);
     86 	  goto done;
     87 	}
     88 
     89       if (order == 1
     90 	  && size == sizeof (mp_limb_t)
     91 	  && endian == HOST_ENDIAN
     92 	  && align == 0)
     93 	{
     94 	  MPN_REVERSE (zp, (mp_srcptr) data, (mp_size_t) count);
     95 	  goto done;
     96 	}
     97     }
     98 
     99   {
    100     mp_limb_t      limb, byte, wbitsmask;
    101     size_t         i, j, numb, wbytes;
    102     mp_size_t      woffset;
    103     unsigned char  *dp;
    104     int            lbits, wbits;
    105 
    106     numb = size * 8 - nail;
    107 
    108     /* whole bytes to process */
    109     wbytes = numb / 8;
    110 
    111     /* partial byte to process */
    112     wbits = numb % 8;
    113     wbitsmask = (CNST_LIMB(1) << wbits) - 1;
    114 
    115     /* offset to get to the next word after processing wbytes and wbits */
    116     woffset = (numb + 7) / 8;
    117     woffset = (endian >= 0 ? woffset : -woffset)
    118       + (order < 0 ? size : - (mp_size_t) size);
    119 
    120     /* least significant byte */
    121     dp = (unsigned char *) data
    122       + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0);
    123 
    124 #define ACCUMULATE(N)                                   \
    125     do {                                                \
    126       ASSERT (lbits < GMP_NUMB_BITS);                   \
    127       ASSERT (limb <= (CNST_LIMB(1) << lbits) - 1);     \
    128                                                         \
    129       limb |= (mp_limb_t) byte << lbits;                \
    130       lbits += (N);                                     \
    131       if (lbits >= GMP_NUMB_BITS)                       \
    132         {                                               \
    133           *zp++ = limb & GMP_NUMB_MASK;                 \
    134           lbits -= GMP_NUMB_BITS;                       \
    135           ASSERT (lbits < (N));                         \
    136           limb = byte >> ((N) - lbits);                 \
    137         }                                               \
    138     } while (0)
    139 
    140     limb = 0;
    141     lbits = 0;
    142     for (i = 0; i < count; i++)
    143       {
    144 	for (j = 0; j < wbytes; j++)
    145 	  {
    146 	    byte = *dp;
    147 	    dp -= endian;
    148 	    ACCUMULATE (8);
    149 	  }
    150 	if (wbits != 0)
    151 	  {
    152 	    byte = *dp & wbitsmask;
    153 	    dp -= endian;
    154 	    ACCUMULATE (wbits);
    155 	  }
    156 	dp += woffset;
    157       }
    158 
    159     if (lbits != 0)
    160       {
    161 	ASSERT (lbits <= GMP_NUMB_BITS);
    162 	ASSERT_LIMB (limb);
    163 	*zp++ = limb;
    164       }
    165 
    166     ASSERT (zp == PTR(z) + zsize);
    167 
    168     /* low byte of word after most significant */
    169     ASSERT (dp == (unsigned char *) data
    170 	    + (order < 0 ? count*size : - (mp_size_t) size)
    171 	    + (endian >= 0 ? (mp_size_t) size - 1 : 0));
    172 
    173   }
    174 
    175  done:
    176   zp = PTR(z);
    177   MPN_NORMALIZE (zp, zsize);
    178   SIZ(z) = zsize;
    179 }
    180