xref: /netbsd-src/external/lgpl3/gmp/dist/mpz/inp_raw.c (revision 4e23f5f9be99587b8f44e2600456853776a02ff8)
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