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