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 the GNU Lesser General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or (at your 10 option) any later version. 11 12 The GNU MP Library is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ 19 20 #include <stdio.h> 21 #include "gmp.h" 22 #include "gmp-impl.h" 23 24 25 26 #if HAVE_LIMB_BIG_ENDIAN 27 #define HOST_ENDIAN 1 28 #endif 29 #if HAVE_LIMB_LITTLE_ENDIAN 30 #define HOST_ENDIAN (-1) 31 #endif 32 #ifndef HOST_ENDIAN 33 static const mp_limb_t endian_test = (CNST_LIMB(1) << (GMP_LIMB_BITS-7)) - 1; 34 #define HOST_ENDIAN (* (signed char *) &endian_test) 35 #endif 36 37 38 void 39 mpz_import (mpz_ptr z, size_t count, int order, 40 size_t size, int endian, size_t nail, const void *data) 41 { 42 mp_size_t zsize; 43 mp_ptr zp; 44 45 ASSERT (order == 1 || order == -1); 46 ASSERT (endian == 1 || endian == 0 || endian == -1); 47 ASSERT (nail <= 8*size); 48 49 zsize = (count * (8*size - nail) + GMP_NUMB_BITS-1) / GMP_NUMB_BITS; 50 zp = MPZ_REALLOC (z, zsize); 51 52 if (endian == 0) 53 endian = HOST_ENDIAN; 54 55 /* Can't use these special cases with nails currently, since they don't 56 mask out the nail bits in the input data. */ 57 if (nail == 0 && GMP_NAIL_BITS == 0) 58 { 59 unsigned align = ((char *) data - (char *) NULL) % sizeof (mp_limb_t); 60 61 if (order == -1 62 && size == sizeof (mp_limb_t) 63 && endian == HOST_ENDIAN 64 && align == 0) 65 { 66 MPN_COPY (zp, (mp_srcptr) data, (mp_size_t) count); 67 goto done; 68 } 69 70 if (order == -1 71 && size == sizeof (mp_limb_t) 72 && endian == - HOST_ENDIAN 73 && align == 0) 74 { 75 MPN_BSWAP (zp, (mp_srcptr) data, (mp_size_t) count); 76 goto done; 77 } 78 79 if (order == 1 80 && size == sizeof (mp_limb_t) 81 && endian == HOST_ENDIAN 82 && align == 0) 83 { 84 MPN_REVERSE (zp, (mp_srcptr) data, (mp_size_t) count); 85 goto done; 86 } 87 } 88 89 { 90 mp_limb_t limb, byte, wbitsmask; 91 size_t i, j, numb, wbytes; 92 mp_size_t woffset; 93 unsigned char *dp; 94 int lbits, wbits; 95 96 numb = size * 8 - nail; 97 98 /* whole bytes to process */ 99 wbytes = numb / 8; 100 101 /* partial byte to process */ 102 wbits = numb % 8; 103 wbitsmask = (CNST_LIMB(1) << wbits) - 1; 104 105 /* offset to get to the next word after processing wbytes and wbits */ 106 woffset = (numb + 7) / 8; 107 woffset = (endian >= 0 ? woffset : -woffset) 108 + (order < 0 ? size : - (mp_size_t) size); 109 110 /* least significant byte */ 111 dp = (unsigned char *) data 112 + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0); 113 114 #define ACCUMULATE(N) \ 115 do { \ 116 ASSERT (lbits < GMP_NUMB_BITS); \ 117 ASSERT (limb <= (CNST_LIMB(1) << lbits) - 1); \ 118 \ 119 limb |= (mp_limb_t) byte << lbits; \ 120 lbits += (N); \ 121 if (lbits >= GMP_NUMB_BITS) \ 122 { \ 123 *zp++ = limb & GMP_NUMB_MASK; \ 124 lbits -= GMP_NUMB_BITS; \ 125 ASSERT (lbits < (N)); \ 126 limb = byte >> ((N) - lbits); \ 127 } \ 128 } while (0) 129 130 limb = 0; 131 lbits = 0; 132 for (i = 0; i < count; i++) 133 { 134 for (j = 0; j < wbytes; j++) 135 { 136 byte = *dp; 137 dp -= endian; 138 ACCUMULATE (8); 139 } 140 if (wbits != 0) 141 { 142 byte = *dp & wbitsmask; 143 dp -= endian; 144 ACCUMULATE (wbits); 145 } 146 dp += woffset; 147 } 148 149 if (lbits != 0) 150 { 151 ASSERT (lbits <= GMP_NUMB_BITS); 152 ASSERT_LIMB (limb); 153 *zp++ = limb; 154 } 155 156 ASSERT (zp == PTR(z) + zsize); 157 158 /* low byte of word after most significant */ 159 ASSERT (dp == (unsigned char *) data 160 + (order < 0 ? count*size : - (mp_size_t) size) 161 + (endian >= 0 ? (mp_size_t) size - 1 : 0)); 162 163 } 164 165 done: 166 zp = PTR(z); 167 MPN_NORMALIZE (zp, zsize); 168 SIZ(z) = zsize; 169 } 170