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