1/* mpz_inp_raw -- read an mpz_t in raw format.
2
3Copyright 2001, 2002, 2005, 2012, 2016 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/* 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
63size_t
64mpz_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