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