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