xref: /netbsd-src/external/lgpl3/mpfr/dist/src/fpif.c (revision ba125506a622fe649968631a56eba5d42ff57863)
1 /* mpfr_fpif -- Binary export & import of MPFR numbers
2    (floating-point interchange format)
3 
4 Copyright 2012-2023 Free Software Foundation, Inc.
5 Contributed by Olivier Demengeon.
6 
7 This file is part of the GNU MPFR Library.
8 
9 The GNU MPFR Library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13 
14 The GNU MPFR Library is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17 License for more details.
18 
19 You should have received a copy of the GNU Lesser General Public License
20 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
21 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
22 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
23 
24 #include "mpfr-impl.h"
25 
26 #if !defined (HAVE_BIG_ENDIAN) && !defined (HAVE_LITTLE_ENDIAN)
27 #error "Endianness is unknown. Not supported yet."
28 #endif
29 
30 /* The format is described as follows. Any multi-byte number is encoded
31    in little endian.
32 
33    1. We first store the precision p (this format is able to represent
34       any precision from 1 to 2^64 + 248).
35       Let B be the first byte (0 <= B <= 255).
36         * If B >= 8, the precision p is B-7.
37           Here, the condition is equivalent to 1 <= p <= 248.
38         * If B <= 7, the next B+1 bytes contain p-249.
39           Here, the condition is equivalent to 249 <= p <= 2^64 + 248.
40       We will use the following macros:
41         * MPFR_MAX_PRECSIZE = 7
42         * MPFR_MAX_EMBEDDED_PRECISION = 255 - 7 = 248
43 
44    2. Then we store the sign bit and exponent related information
45       (possibly a special value). We first have byte A = [seeeeeee],
46       where s is the sign bit and E = [eeeeeee] such that:
47         * If 0 <= E <= 94, then the exponent e is E-47 (-47 <= e <= 47).
48         * If 95 <= E <= 110, the exponent is stored in the next E-94 bytes
49           (1 to 16 bytes) in sign + absolute value representation,
50           where the absolute value is increased by 47 (e <= -47 or 47 <= e).
51         * If 111 <= E <= 118, the exponent size S is stored in the next
52           E-110 bytes (1 to 8), then the exponent itself is stored in the
53           next S bytes. [Not implemented yet]
54         * If 119 <= E <= 127, we have a special value:
55           E = 119 (MPFR_KIND_ZERO) for a signed zero;
56           E = 120 (MPFR_KIND_INF) for a signed infinity;
57           E = 121 (MPFR_KIND_NAN) for NaN.
58 
59    3. Then we store the significand (for regular values).
60 
61    The sign bit is preserved by the import/export functions, even for NaN.
62 
63    Note: When a size is stored, it must be minimal, i.e. a number cannot
64    start with a null byte. Otherwise the import may fail.
65 */
66 
67 #define MPFR_MAX_PRECSIZE 7
68 #define MPFR_MAX_EMBEDDED_PRECISION (255 - MPFR_MAX_PRECSIZE)
69 
70 #define MPFR_KIND_ZERO 119
71 #define MPFR_KIND_INF 120
72 #define MPFR_KIND_NAN 121
73 #define MPFR_MAX_EMBEDDED_EXPONENT 47
74 #define MPFR_EXTERNAL_EXPONENT 94
75 
76 /* Begin: Low level helper functions */
77 
78 /* storage must have an unsigned type */
79 #define COUNT_NB_BYTE(storage, size)            \
80   do                                            \
81     {                                           \
82       (storage) >>= 8;                          \
83       (size)++;                                 \
84     }                                           \
85   while ((storage) != 0)
86 
87 #define ALLOC_RESULT(buffer, buffer_size, wanted_size)                  \
88   do                                                                    \
89     {                                                                   \
90       if ((buffer) == NULL || *(buffer_size) < (wanted_size))           \
91         {                                                               \
92           (buffer) = (unsigned char *) mpfr_reallocate_func             \
93             ((buffer), *(buffer_size), (wanted_size));                  \
94           MPFR_ASSERTN((buffer) != 0);                                  \
95         }                                                               \
96       *(buffer_size) = (wanted_size);                                   \
97     }                                                                   \
98   while (0)
99 
100 /*
101  * size in byte of a MPFR number in a binary object of a variable size
102  */
103 #define MAX_VARIABLE_STORAGE(exponent_size, precision) \
104   ((size_t)(((precision) >> 3) + (exponent_size) +     \
105             ((precision) > 248 ? sizeof(mpfr_prec_t) : 0) + 3))
106 
107 /* copy in result[] the values in data[] with a different endianness,
108    where data_size might be smaller than data_max_size, so that we only
109    copy data_size bytes from the end of data[]. */
110 static void
111 #if defined (HAVE_BIG_ENDIAN)
putLittleEndianData(unsigned char * result,unsigned char * data,size_t data_max_size,size_t data_size)112 putLittleEndianData (unsigned char *result, unsigned char *data,
113                      size_t data_max_size, size_t data_size)
114 #elif defined (HAVE_LITTLE_ENDIAN)
115 putBigEndianData (unsigned char *result, unsigned char *data,
116                   size_t data_max_size, size_t data_size)
117 #endif
118 {
119   size_t j;
120 
121   MPFR_ASSERTD (data_size <= data_max_size);
122   for (j = 0; j < data_size; j++)
123     result[j] = data[data_max_size - j - 1];
124 }
125 
126 /* copy in result[] the values in data[] with the same endianness */
127 static void
128 #if defined (HAVE_BIG_ENDIAN)
putBigEndianData(unsigned char * result,unsigned char * data,size_t data_max_size,size_t data_size)129 putBigEndianData (unsigned char *result, unsigned char *data,
130                   size_t data_max_size, size_t data_size)
131 #elif defined (HAVE_LITTLE_ENDIAN)
132 putLittleEndianData (unsigned char *result, unsigned char *data,
133                      size_t data_max_size, size_t data_size)
134 #endif
135 {
136   MPFR_ASSERTD (data_size <= data_max_size);
137   memcpy (result, data, data_size);
138 }
139 
140 /* copy in result[] the values in data[] with a different endianness;
141    the data are written at the end of the result[] buffer (if
142    data_size < data_max_size, the first bytes of result[] are
143    left untouched). */
144 static void
145 #if defined (HAVE_BIG_ENDIAN)
getLittleEndianData(unsigned char * result,unsigned char * data,size_t data_max_size,size_t data_size)146 getLittleEndianData (unsigned char *result, unsigned char *data,
147                      size_t data_max_size, size_t data_size)
148 #elif defined (HAVE_LITTLE_ENDIAN)
149 getBigEndianData (unsigned char *result, unsigned char *data,
150                   size_t data_max_size, size_t data_size)
151 #endif
152 {
153   size_t j;
154 
155   MPFR_ASSERTD (data_size <= data_max_size);
156   for (j = 0; j < data_size; j++)
157     result[data_max_size - j - 1] = data[j];
158 }
159 
160 /* copy in result[] the values in data[] with the same endianness */
161 static void
162 #if defined (HAVE_BIG_ENDIAN)
getBigEndianData(unsigned char * result,unsigned char * data,size_t data_max_size,size_t data_size)163 getBigEndianData (unsigned char *result, unsigned char *data,
164                   size_t data_max_size, size_t data_size)
165 #elif defined (HAVE_LITTLE_ENDIAN)
166 getLittleEndianData (unsigned char *result, unsigned char *data,
167                      size_t data_max_size, size_t data_size)
168 #endif
169 {
170   MPFR_ASSERTD (data_size <= data_max_size);
171   memcpy (result, data, data_size);
172 }
173 
174 /* End: Low level helper functions */
175 
176 /* Internal Function */
177 /*
178  * buffer : OUT : store the precision in binary format, can be null
179  *               (may be reallocated if too small)
180  * buffer_size : IN/OUT : size of the buffer => size used in the buffer
181  * precision : IN : precision to store
182  * return pointer to a buffer storing the precision in binary format
183  */
184 static unsigned char *
mpfr_fpif_store_precision(unsigned char * buffer,size_t * buffer_size,mpfr_prec_t precision)185 mpfr_fpif_store_precision (unsigned char *buffer, size_t *buffer_size,
186                            mpfr_prec_t precision)
187 {
188   unsigned char *result;
189   size_t size_precision;
190 
191   MPFR_ASSERTD (precision >= 1);
192   size_precision = 0;
193 
194   if (precision > MPFR_MAX_EMBEDDED_PRECISION)
195     {
196       mpfr_uprec_t copy_precision;
197 
198       copy_precision = precision - (MPFR_MAX_EMBEDDED_PRECISION + 1);
199       COUNT_NB_BYTE(copy_precision, size_precision);
200     }
201 
202   result = buffer;
203   ALLOC_RESULT(result, buffer_size, size_precision + 1);
204 
205   if (precision > MPFR_MAX_EMBEDDED_PRECISION)
206     {
207       result[0] = size_precision - 1;
208       precision -= (MPFR_MAX_EMBEDDED_PRECISION + 1);
209       putLittleEndianData (result + 1, (unsigned char *) &precision,
210                            sizeof(mpfr_prec_t), size_precision);
211     }
212   else
213     result[0] = precision + MPFR_MAX_PRECSIZE;
214 
215   return result;
216 }
217 
218 #define BUFFER_SIZE 8
219 
220 /*
221  * fh : IN : file handler
222  * return the precision stored in the binary buffer, 0 in case of error
223  */
224 static mpfr_prec_t
mpfr_fpif_read_precision_from_file(FILE * fh)225 mpfr_fpif_read_precision_from_file (FILE *fh)
226 {
227   mpfr_prec_t precision;
228   size_t precision_size;
229   unsigned char buffer[BUFFER_SIZE];
230 
231   if (fh == NULL)
232     return 0;
233 
234   if (fread (buffer, 1, 1, fh) != 1)
235     return 0;
236 
237   precision_size = buffer[0];
238   if (precision_size > MPFR_MAX_PRECSIZE)
239     return precision_size - MPFR_MAX_PRECSIZE;
240 
241   precision_size++;
242   MPFR_ASSERTD (precision_size <= BUFFER_SIZE);
243 
244   /* Read the precision in little-endian format. */
245   if (fread (buffer, precision_size, 1, fh) != 1)
246     return 0;
247 
248   /* Justification of the #if below. */
249   MPFR_ASSERTD (precision_size <= MPFR_MAX_PRECSIZE + 1);
250 
251 #if (MPFR_MAX_PRECSIZE + 1) * CHAR_BIT > MPFR_PREC_BITS
252   while (precision_size > sizeof(mpfr_prec_t))
253     {
254       if (buffer[precision_size-1] != 0)
255         return 0;  /* the read precision doesn't fit in a mpfr_prec_t */
256       precision_size--;
257     }
258 #endif
259 
260   /* To detect bugs affecting particular platforms (thus MPFR_ASSERTN)... */
261   MPFR_ASSERTN (precision_size <= sizeof(mpfr_prec_t));
262 
263   /* Since mpfr_prec_t is signed, one also needs to check that the
264      most significant bit of the corresponding unsigned value is 0. */
265   if (precision_size == sizeof(mpfr_prec_t) &&
266       buffer[precision_size-1] >= 0x80)
267     return 0;  /* the read precision doesn't fit in a mpfr_prec_t */
268 
269   precision = 0;  /* to pad with 0's if data_size < data_max_size */
270 
271   /* On big-endian machines, the data must be copied at the end of the
272      precision object in the memory; thus data_max_size (3rd argument)
273      must be sizeof(mpfr_prec_t). */
274   getLittleEndianData ((unsigned char *) &precision, buffer,
275                        sizeof(mpfr_prec_t), precision_size);
276 
277   return precision + (MPFR_MAX_EMBEDDED_PRECISION + 1);
278 }
279 
280 /*
281  * buffer : OUT : store the kind of the MPFR number x, its sign, the size of
282  *                its exponent and its exponent value in a binary format,
283  *                can be null (may be reallocated if too small)
284  * buffer_size : IN/OUT : size of the buffer => size used in the buffer
285  * x : IN : MPFR number
286  * return pointer to a buffer storing the kind of the MPFR number x, its sign,
287  *        the size of its exponent and its exponent value in a binary format,
288  */
289 /* TODO
290  *   Exponents that use more than 16 bytes are not managed (not an issue
291  *   until one has integer types larger than 128 bits).
292  */
293 static unsigned char*
mpfr_fpif_store_exponent(unsigned char * buffer,size_t * buffer_size,mpfr_ptr x)294 mpfr_fpif_store_exponent (unsigned char *buffer, size_t *buffer_size,
295                           mpfr_ptr x)
296 {
297   unsigned char *result;
298   mpfr_uexp_t uexp;
299   size_t exponent_size;
300 
301   exponent_size = 0;
302 
303   if (MPFR_IS_PURE_FP (x))
304     {
305       mpfr_exp_t exponent = MPFR_GET_EXP (x);
306 
307       if (exponent > MPFR_MAX_EMBEDDED_EXPONENT ||
308           exponent < -MPFR_MAX_EMBEDDED_EXPONENT)
309         {
310           mpfr_uexp_t copy_exponent, exp_sign_bit;
311 
312           uexp = SAFE_ABS (mpfr_uexp_t, exponent)
313             - MPFR_MAX_EMBEDDED_EXPONENT;
314 
315           /* Shift uexp to take the sign bit of the exponent into account.
316              Because of constraints on the valid exponents, this cannot
317              overflow (check with an MPFR_ASSERTD). */
318           copy_exponent = uexp << 1;
319           MPFR_ASSERTD (copy_exponent > uexp);
320           COUNT_NB_BYTE(copy_exponent, exponent_size);
321           MPFR_ASSERTN (exponent_size <= 16);  /* see TODO */
322 
323           /* Sign bit of the exponent. */
324           exp_sign_bit = (mpfr_uexp_t) 1 << (8 * exponent_size - 1);
325           MPFR_ASSERTD (uexp < exp_sign_bit);
326           if (exponent < 0)
327             uexp |= exp_sign_bit;
328         }
329       else
330         uexp = exponent + MPFR_MAX_EMBEDDED_EXPONENT;
331     }
332 
333   result = buffer;
334   ALLOC_RESULT(result, buffer_size, exponent_size + 1);
335 
336   if (MPFR_IS_PURE_FP (x))
337     {
338       if (exponent_size == 0)
339         result[0] = uexp;
340       else
341         {
342           result[0] = MPFR_EXTERNAL_EXPONENT + exponent_size;
343 
344           putLittleEndianData (result + 1, (unsigned char *) &uexp,
345                                sizeof(mpfr_exp_t), exponent_size);
346         }
347     }
348   else if (MPFR_IS_ZERO (x))
349     result[0] = MPFR_KIND_ZERO;
350   else if (MPFR_IS_INF (x))
351     result[0] = MPFR_KIND_INF;
352   else
353     {
354       MPFR_ASSERTD (MPFR_IS_NAN (x));
355       result[0] = MPFR_KIND_NAN;
356     }
357 
358   /* Set the sign, even for NaN. */
359   if (MPFR_IS_NEG (x))
360     result[0] |= 0x80;
361 
362   return result;
363 }
364 
365 /*
366  * x : OUT : MPFR number extracted from the binary buffer
367  * fh : IN : file handler (should not be NULL)
368  * return 0 if successful
369  */
370 /* TODO
371  *   Exponents that use more than 16 bytes are not managed (this is not
372  *   an issue if the data were written by MPFR with mpfr_exp_t not larger
373  *   than 128 bits).
374  */
375 static int
mpfr_fpif_read_exponent_from_file(mpfr_ptr x,FILE * fh)376 mpfr_fpif_read_exponent_from_file (mpfr_ptr x, FILE * fh)
377 {
378   mpfr_exp_t exponent;
379   mpfr_uexp_t uexp;
380   size_t exponent_size;
381   int sign;
382   unsigned char buffer[sizeof(mpfr_exp_t)];
383 
384   MPFR_ASSERTD(fh != NULL);
385 
386   if (fread (buffer, 1, 1, fh) != 1)
387     return 1;
388 
389   /* sign value that can be used with MPFR_SET_SIGN,
390      mpfr_set_zero and mpfr_set_inf */
391   sign = (buffer[0] & 0x80) ? MPFR_SIGN_NEG : MPFR_SIGN_POS;
392   /* Set the sign, even for NaN. */
393   MPFR_SET_SIGN (x, sign);
394 
395   exponent = buffer[0] & 0x7F;
396   exponent_size = 1;
397 
398   if (exponent > MPFR_EXTERNAL_EXPONENT && exponent < MPFR_KIND_ZERO)
399     {
400       mpfr_uexp_t exp_sign_bit;
401 
402       exponent_size = exponent - MPFR_EXTERNAL_EXPONENT;
403 
404       /* A failure is acceptable when the exponent starts with leading zeros,
405          even if it would fit in mpfr_exp_t (see format description). */
406       if (MPFR_UNLIKELY (exponent_size > 16 /* see TODO */ ||
407                          exponent_size > sizeof(mpfr_exp_t)))
408         return 1;
409 
410       if (MPFR_UNLIKELY (fread (buffer, exponent_size, 1, fh) != 1))
411         return 1;
412 
413       uexp = 0;
414       getLittleEndianData ((unsigned char *) &uexp, buffer,
415                            sizeof(mpfr_exp_t), exponent_size);
416 
417       /* Sign bit of the exponent. */
418       exp_sign_bit = uexp & ((mpfr_uexp_t) 1 << (8 * exponent_size - 1));
419 
420       uexp &= ~exp_sign_bit;
421       uexp += MPFR_MAX_EMBEDDED_EXPONENT;
422       if (MPFR_UNLIKELY (uexp > MPFR_EMAX_MAX && uexp > -MPFR_EMIN_MIN))
423         return 1;
424 
425       exponent = exp_sign_bit ? - (mpfr_exp_t) uexp : (mpfr_exp_t) uexp;
426       if (MPFR_UNLIKELY (! MPFR_EXP_IN_RANGE (exponent)))
427         return 1;
428       MPFR_SET_EXP (x, exponent);
429 
430       exponent_size++;
431     }
432   else if (exponent == MPFR_KIND_ZERO)
433     MPFR_SET_ZERO (x);
434   else if (exponent == MPFR_KIND_INF)
435     MPFR_SET_INF (x);
436   else if (exponent == MPFR_KIND_NAN)
437     MPFR_SET_NAN (x);
438   else if (exponent <= MPFR_EXTERNAL_EXPONENT)
439     {
440       exponent -= MPFR_MAX_EMBEDDED_EXPONENT;
441       if (MPFR_UNLIKELY (! MPFR_EXP_IN_RANGE (exponent)))
442         return 1;
443       MPFR_SET_EXP (x, exponent);
444     }
445   else
446     return 1;
447 
448   return 0;
449 }
450 
451 /*
452  * buffer : OUT : store the limb of the MPFR number x in a binary format,
453  *                can be null (may be reallocated if too small)
454  * buffer_size : IN/OUT : size of the buffer => size used in the buffer
455  * x : IN : MPFR number
456  * return pointer to a buffer storing the limb of the MPFR number x in a binary
457  *        format
458  */
459 static unsigned char*
mpfr_fpif_store_limbs(unsigned char * buffer,size_t * buffer_size,mpfr_ptr x)460 mpfr_fpif_store_limbs (unsigned char *buffer, size_t *buffer_size, mpfr_ptr x)
461 {
462   unsigned char *result;
463   mpfr_prec_t precision;
464   size_t nb_byte;
465   size_t nb_limb, mp_bytes_per_limb;
466   size_t nb_partial_byte;
467   size_t i, j;
468 
469   precision = mpfr_get_prec (x);
470   nb_byte = (precision + 7) >> 3;
471   mp_bytes_per_limb = mp_bits_per_limb >> 3;
472   nb_partial_byte = nb_byte % mp_bytes_per_limb;
473   nb_limb = (nb_byte + mp_bytes_per_limb - 1) / mp_bytes_per_limb;
474 
475   result = buffer;
476   ALLOC_RESULT(result, buffer_size, nb_byte);
477 
478   putBigEndianData (result, (unsigned char*) MPFR_MANT(x),
479                     sizeof(mp_limb_t), nb_partial_byte);
480   for (i = nb_partial_byte, j = (nb_partial_byte == 0) ? 0 : 1; j < nb_limb;
481        i += mp_bytes_per_limb, j++)
482     putLittleEndianData (result + i, (unsigned char*) (MPFR_MANT(x) + j),
483                          sizeof(mp_limb_t), sizeof(mp_limb_t));
484 
485   return result;
486 }
487 
488 /*
489  * x : OUT : MPFR number extracted from the binary buffer, should have the same
490  *           precision than the number in the binary format
491  * buffer : IN : limb of the MPFR number x in a binary format
492  * nb_byte : IN : size of the buffer (in bytes)
493  * Assume buffer is not NULL.
494  */
495 static void
mpfr_fpif_read_limbs(mpfr_ptr x,unsigned char * buffer,size_t nb_byte)496 mpfr_fpif_read_limbs (mpfr_ptr x, unsigned char *buffer, size_t nb_byte)
497 {
498   size_t mp_bytes_per_limb;
499   size_t nb_partial_byte;
500   size_t i, j;
501 
502   MPFR_ASSERTD (buffer != NULL);
503 
504   mp_bytes_per_limb = mp_bits_per_limb >> 3;
505   nb_partial_byte = nb_byte % mp_bytes_per_limb;
506 
507   if (nb_partial_byte > 0)
508     {
509       memset (MPFR_MANT(x), 0, sizeof(mp_limb_t));
510       getBigEndianData ((unsigned char*) MPFR_MANT(x), buffer,
511                         sizeof(mp_limb_t), nb_partial_byte);
512     }
513   for (i = nb_partial_byte, j = (nb_partial_byte == 0) ? 0 : 1; i < nb_byte;
514        i += mp_bytes_per_limb, j++)
515     getLittleEndianData ((unsigned char*) (MPFR_MANT(x) + j), buffer + i,
516                          sizeof(mp_limb_t), sizeof(mp_limb_t));
517 }
518 
519 /* External Function */
520 /*
521  * fh : IN : file handler
522  * x : IN : MPFR number to put in the file
523  * return 0 if successful
524  */
525 int
mpfr_fpif_export(FILE * fh,mpfr_ptr x)526 mpfr_fpif_export (FILE *fh, mpfr_ptr x)
527 {
528   int status;
529   unsigned char *buf;
530   unsigned char *bufResult;
531   size_t used_size, buf_size;
532 
533   if (fh == NULL)
534     return -1;
535 
536   buf_size = MAX_VARIABLE_STORAGE(sizeof(mpfr_exp_t), mpfr_get_prec (x));
537   buf = (unsigned char*) mpfr_allocate_func (buf_size);
538   MPFR_ASSERTN(buf != NULL);
539 
540   used_size = buf_size;
541   buf = mpfr_fpif_store_precision (buf, &used_size, mpfr_get_prec (x));
542   used_size > buf_size ? buf_size = used_size : 0;
543   status = fwrite (buf, used_size, 1, fh);
544   if (status != 1)
545     {
546       mpfr_free_func (buf, buf_size);
547       return -1;
548     }
549   used_size = buf_size;
550   bufResult = mpfr_fpif_store_exponent (buf, &used_size, x);
551   /* bufResult cannot be NULL: if reallocation failed in
552      mpfr_fpif_store_exponent, an assertion failed */
553   buf = bufResult;
554   used_size > buf_size ? buf_size = used_size : 0;
555   status = fwrite (buf, used_size, 1, fh);
556   if (status != 1)
557     {
558       mpfr_free_func (buf, buf_size);
559       return -1;
560     }
561 
562   if (mpfr_regular_p (x))
563     {
564       used_size = buf_size;
565       buf = mpfr_fpif_store_limbs (buf, &used_size, x);
566       used_size > buf_size ? buf_size = used_size : 0;
567       status = fwrite (buf, used_size, 1, fh);
568       if (status != 1)
569         {
570           mpfr_free_func (buf, buf_size);
571           return -1;
572         }
573     }
574 
575   mpfr_free_func (buf, buf_size);
576   return 0;
577 }
578 
579 /*
580  * x : IN/OUT : MPFR number extracted from the file, its precision is reset to
581  *              be able to hold the number
582  * fh : IN : file handler
583  * Return 0 if the import was successful.
584  */
585 int
mpfr_fpif_import(mpfr_ptr x,FILE * fh)586 mpfr_fpif_import (mpfr_ptr x, FILE *fh)
587 {
588   int status;
589   mpfr_prec_t precision;
590   unsigned char *buffer;
591   size_t used_size;
592 
593   precision = mpfr_fpif_read_precision_from_file (fh);
594   if (precision == 0) /* precision = 0 means an error */
595     return -1;
596   MPFR_ASSERTD(fh != NULL); /* checked by mpfr_fpif_read_precision_from_file */
597   if (precision > MPFR_PREC_MAX)
598     return -1;
599   MPFR_STAT_STATIC_ASSERT (MPFR_PREC_MIN == 1);  /* as specified */
600   mpfr_set_prec (x, precision);
601 
602   status = mpfr_fpif_read_exponent_from_file (x, fh);
603   if (status != 0)
604     {
605       mpfr_set_nan (x);
606       return -1;
607     }
608 
609   /* Warning! The significand of x is not set yet. Thus use MPFR_IS_SINGULAR
610      for the test. */
611   if (!MPFR_IS_SINGULAR (x))
612     {
613       /* For portability, we need to consider bytes with only 8 significant
614          bits in the interchange format. That's OK because CHAR_BIT >= 8.
615          But the implementation is currently not clear when CHAR_BIT > 8.
616          This may have never been tested. For safety, require CHAR_BIT == 8,
617          and test/adapt the code if this ever fails. */
618       MPFR_STAT_STATIC_ASSERT (CHAR_BIT == 8);
619       MPFR_STAT_STATIC_ASSERT ((MPFR_PREC_MAX + 7) >> 3 <= (size_t) -1);
620       used_size = (precision + 7) >> 3; /* ceil(precision/8) */
621       buffer = (unsigned char*) mpfr_allocate_func (used_size);
622       MPFR_ASSERTN(buffer != NULL);
623       status = fread (buffer, used_size, 1, fh);
624       if (status != 1)
625         {
626           mpfr_free_func (buffer, used_size);
627           mpfr_set_nan (x);
628           return -1;
629         }
630       mpfr_fpif_read_limbs (x, buffer, used_size);
631       mpfr_free_func (buffer, used_size);
632     }
633 
634   return 0;
635 }
636