1 /* mpz_inp_raw -- read an mpz_t in raw format.
2
3 Copyright 2001, 2002, 2005, 2012, 2016 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 /* NTOH_LIMB_FETCH fetches a limb which is in network byte order (ie. big
36 endian) and produces a normal host byte order result. */
37
38 #if HAVE_LIMB_BIG_ENDIAN
39 #define NTOH_LIMB_FETCH(limb, src) do { (limb) = *(src); } while (0)
40 #endif
41
42 #if HAVE_LIMB_LITTLE_ENDIAN
43 #define NTOH_LIMB_FETCH(limb, src) BSWAP_LIMB_FETCH (limb, src)
44 #endif
45
46 #ifndef NTOH_LIMB_FETCH
47 #define NTOH_LIMB_FETCH(limb, src) \
48 do { \
49 const unsigned char *__p = (const unsigned char *) (src); \
50 mp_limb_t __limb; \
51 int __i; \
52 __limb = 0; \
53 for (__i = 0; __i < GMP_LIMB_BYTES; __i++) \
54 __limb = (__limb << 8) | __p[__i]; \
55 (limb) = __limb; \
56 } while (0)
57 #endif
58
59
60 /* Enhancement: The byte swap loop ought to be safe to vectorize on Cray
61 etc, but someone who knows what they're doing needs to check it. */
62
63 size_t
mpz_inp_raw(mpz_ptr x,FILE * fp)64 mpz_inp_raw (mpz_ptr x, FILE *fp)
65 {
66 unsigned char csize_bytes[4];
67 mp_size_t csize, abs_xsize, i;
68 size_t size;
69 size_t abs_csize;
70 char *cp;
71 mp_ptr xp, sp, ep;
72 mp_limb_t slimb, elimb;
73
74 if (fp == 0)
75 fp = stdin;
76
77 /* 4 bytes for size */
78 if (fread (csize_bytes, sizeof (csize_bytes), 1, fp) != 1)
79 return 0;
80
81 size = (((size_t) csize_bytes[0] << 24) + ((size_t) csize_bytes[1] << 16) +
82 ((size_t) csize_bytes[2] << 8) + ((size_t) csize_bytes[3]));
83
84 if (size < 0x80000000u)
85 csize = size;
86 else
87 csize = size - 0x80000000u - 0x80000000u;
88
89 abs_csize = ABS (csize);
90
91 if (UNLIKELY (abs_csize > ~(mp_bitcnt_t) 0 / 8))
92 return 0; /* Bit size overflows */
93
94 /* round up to a multiple of limbs */
95 abs_xsize = BITS_TO_LIMBS ((mp_bitcnt_t) abs_csize * 8);
96
97 if (abs_xsize != 0)
98 {
99 xp = MPZ_NEWALLOC (x, abs_xsize);
100
101 /* Get limb boundaries right in the read, for the benefit of the
102 non-nails case. */
103 xp[0] = 0;
104 cp = (char *) (xp + abs_xsize) - abs_csize;
105 if (fread (cp, abs_csize, 1, fp) != 1)
106 return 0;
107
108 if (GMP_NAIL_BITS == 0)
109 {
110 /* Reverse limbs to least significant first, and byte swap. If
111 abs_xsize is odd then on the last iteration elimb and slimb are
112 the same. It doesn't seem extra code to handle that case
113 separately, to save an NTOH. */
114 sp = xp;
115 ep = xp + abs_xsize-1;
116 for (i = 0; i < (abs_xsize+1)/2; i++)
117 {
118 NTOH_LIMB_FETCH (elimb, ep);
119 NTOH_LIMB_FETCH (slimb, sp);
120 *sp++ = elimb;
121 *ep-- = slimb;
122 }
123 }
124 else
125 {
126 /* It ought to be possible to do the transformation in-place, but
127 for now it's easier to use an extra temporary area. */
128 mp_limb_t byte, limb;
129 int bits;
130 mp_size_t tpos;
131 mp_ptr tp;
132 TMP_DECL;
133
134 TMP_MARK;
135 tp = TMP_ALLOC_LIMBS (abs_xsize);
136 limb = 0;
137 bits = 0;
138 tpos = 0;
139 for (i = abs_csize-1; i >= 0; i--)
140 {
141 byte = (unsigned char) cp[i];
142 limb |= (byte << bits);
143 bits += 8;
144 if (bits >= GMP_NUMB_BITS)
145 {
146 ASSERT (tpos < abs_xsize);
147 tp[tpos++] = limb & GMP_NUMB_MASK;
148 bits -= GMP_NUMB_BITS;
149 ASSERT (bits < 8);
150 limb = byte >> (8 - bits);
151 }
152 }
153 if (bits != 0)
154 {
155 ASSERT (tpos < abs_xsize);
156 tp[tpos++] = limb;
157 }
158 ASSERT (tpos == abs_xsize);
159
160 MPN_COPY (xp, tp, abs_xsize);
161 TMP_FREE;
162 }
163
164 /* GMP 1.x mpz_out_raw wrote high zero bytes, strip any high zero
165 limbs resulting from this. Should be a non-zero value here, but
166 for safety don't assume that. */
167 MPN_NORMALIZE (xp, abs_xsize);
168 }
169
170 SIZ(x) = (csize >= 0 ? abs_xsize : -abs_xsize);
171 return abs_csize + 4;
172 }
173