xref: /netbsd-src/external/lgpl3/gmp/dist/mpz/inp_raw.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
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
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   /* round up to a multiple of limbs */
92   abs_xsize = BITS_TO_LIMBS (abs_csize*8);
93 
94   if (abs_xsize != 0)
95     {
96       xp = MPZ_NEWALLOC (x, abs_xsize);
97 
98       /* Get limb boundaries right in the read, for the benefit of the
99 	 non-nails case.  */
100       xp[0] = 0;
101       cp = (char *) (xp + abs_xsize) - abs_csize;
102       if (fread (cp, abs_csize, 1, fp) != 1)
103 	return 0;
104 
105       if (GMP_NAIL_BITS == 0)
106 	{
107 	  /* Reverse limbs to least significant first, and byte swap.  If
108 	     abs_xsize is odd then on the last iteration elimb and slimb are
109 	     the same.  It doesn't seem extra code to handle that case
110 	     separately, to save an NTOH.  */
111 	  sp = xp;
112 	  ep = xp + abs_xsize-1;
113 	  for (i = 0; i < (abs_xsize+1)/2; i++)
114 	    {
115 	      NTOH_LIMB_FETCH (elimb, ep);
116 	      NTOH_LIMB_FETCH (slimb, sp);
117 	      *sp++ = elimb;
118 	      *ep-- = slimb;
119 	    }
120 	}
121       else
122 	{
123 	  /* It ought to be possible to do the transformation in-place, but
124 	     for now it's easier to use an extra temporary area.  */
125 	  mp_limb_t  byte, limb;
126 	  int	     bits;
127 	  mp_size_t  tpos;
128 	  mp_ptr     tp;
129 	  TMP_DECL;
130 
131 	  TMP_MARK;
132 	  tp = TMP_ALLOC_LIMBS (abs_xsize);
133 	  limb = 0;
134 	  bits = 0;
135 	  tpos = 0;
136 	  for (i = abs_csize-1; i >= 0; i--)
137 	    {
138 	      byte = (unsigned char) cp[i];
139 	      limb |= (byte << bits);
140 	      bits += 8;
141 	      if (bits >= GMP_NUMB_BITS)
142 		{
143 		  ASSERT (tpos < abs_xsize);
144 		  tp[tpos++] = limb & GMP_NUMB_MASK;
145 		  bits -= GMP_NUMB_BITS;
146 		  ASSERT (bits < 8);
147 		  limb = byte >> (8 - bits);
148 		}
149 	    }
150 	  if (bits != 0)
151 	    {
152 	      ASSERT (tpos < abs_xsize);
153 	      tp[tpos++] = limb;
154 	    }
155 	  ASSERT (tpos == abs_xsize);
156 
157 	  MPN_COPY (xp, tp, abs_xsize);
158 	  TMP_FREE;
159 	}
160 
161       /* GMP 1.x mpz_out_raw wrote high zero bytes, strip any high zero
162 	 limbs resulting from this.  Should be a non-zero value here, but
163 	 for safety don't assume that. */
164       MPN_NORMALIZE (xp, abs_xsize);
165     }
166 
167   SIZ(x) = (csize >= 0 ? abs_xsize : -abs_xsize);
168   return abs_csize + 4;
169 }
170