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