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
mpz_import(mpz_ptr z,size_t count,int order,size_t size,int endian,size_t nail,const void * data)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