(root)/
mpfr-4.2.1/
src/
fpif.c
       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)
     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)
     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)
     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)
     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 *
     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
     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*
     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
     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*
     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
     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
     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
     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  }