blob: e40b5ed57798a627c5c469f7269738e5c2f8fca4 [file] [log] [blame]
Austin Schuhbb1338c2024-06-15 19:31:16 -07001/* mpz_import -- set mpz from word data.
2
3Copyright 2002, 2012 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it 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
14or
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
20or both in parallel, as here.
21
22The GNU MP Library is distributed in the hope that it will be useful, but
23WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25for more details.
26
27You should have received copies of the GNU General Public License and the
28GNU Lesser General Public License along with the GNU MP Library. If not,
29see 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
43static 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
48void
49mpz_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}