(root)/
gmp-6.3.0/
mpz/
out_raw.c
       1  /* mpz_out_raw -- write an mpz_t in raw format.
       2  
       3  Copyright 2001, 2002 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  #include "longlong.h"
      34  
      35  
      36  /* HTON_LIMB_STORE takes a normal host byte order limb and stores it as
      37     network byte order (ie. big endian). */
      38  
      39  #if HAVE_LIMB_BIG_ENDIAN
      40  #define HTON_LIMB_STORE(dst, limb)  do { *(dst) = (limb); } while (0)
      41  #endif
      42  
      43  #if HAVE_LIMB_LITTLE_ENDIAN
      44  #define HTON_LIMB_STORE(dst, limb)  BSWAP_LIMB_STORE (dst, limb)
      45  #endif
      46  
      47  #ifndef HTON_LIMB_STORE
      48  #define HTON_LIMB_STORE(dst, limb)                                      \
      49    do {                                                                  \
      50      mp_limb_t  __limb = (limb);                                         \
      51      char      *__p = (char *) (dst);                                    \
      52      int        __i;                                                     \
      53      for (__i = 0; __i < GMP_LIMB_BYTES; __i++)                       \
      54        __p[__i] = (char) (__limb >> ((GMP_LIMB_BYTES-1 - __i) * 8));  \
      55    } while (0)
      56  #endif
      57  
      58  
      59  size_t
      60  mpz_out_raw (FILE *fp, mpz_srcptr x)
      61  {
      62    mp_size_t   xsize, abs_xsize, bytes, i;
      63    mp_srcptr   xp;
      64    char        *tp, *bp;
      65    mp_limb_t   xlimb;
      66    int         zeros;
      67    size_t      tsize, ssize;
      68  
      69    xsize = SIZ(x);
      70    abs_xsize = ABS (xsize);
      71    bytes = (abs_xsize * GMP_NUMB_BITS + 7) / 8;
      72    tsize = ROUND_UP_MULTIPLE ((unsigned) 4, GMP_LIMB_BYTES) + bytes;
      73  
      74    tp = __GMP_ALLOCATE_FUNC_TYPE (tsize, char);
      75    bp = tp + ROUND_UP_MULTIPLE ((unsigned) 4, GMP_LIMB_BYTES);
      76  
      77    if (bytes != 0)
      78      {
      79        bp += bytes;
      80        xp = PTR (x);
      81        i = abs_xsize;
      82  
      83        if (GMP_NAIL_BITS == 0)
      84  	{
      85  	  /* reverse limb order, and byte swap if necessary */
      86  #ifdef _CRAY
      87  	  _Pragma ("_CRI ivdep");
      88  #endif
      89  	  do
      90  	    {
      91  	      bp -= GMP_LIMB_BYTES;
      92  	      xlimb = *xp;
      93  	      HTON_LIMB_STORE ((mp_ptr) bp, xlimb);
      94  	      xp++;
      95  	    }
      96  	  while (--i > 0);
      97  
      98  	  /* strip high zero bytes (without fetching from bp) */
      99  	  count_leading_zeros (zeros, xlimb);
     100  	  zeros /= 8;
     101  	  bp += zeros;
     102  	  bytes -= zeros;
     103  	}
     104        else
     105  	{
     106  	  mp_limb_t  new_xlimb;
     107  	  int        bits;
     108  	  ASSERT_CODE (char *bp_orig = bp - bytes);
     109  
     110  	  ASSERT_ALWAYS (GMP_NUMB_BITS >= 8);
     111  
     112  	  bits = 0;
     113  	  xlimb = 0;
     114  	  for (;;)
     115  	    {
     116  	      while (bits >= 8)
     117  		{
     118  		  ASSERT (bp > bp_orig);
     119  		  *--bp = xlimb & 0xFF;
     120  		  xlimb >>= 8;
     121  		  bits -= 8;
     122  		}
     123  
     124  	      if (i == 0)
     125  		break;
     126  
     127  	      new_xlimb = *xp++;
     128  	      i--;
     129  	      ASSERT (bp > bp_orig);
     130  	      *--bp = (xlimb | (new_xlimb << bits)) & 0xFF;
     131  	      xlimb = new_xlimb >> (8 - bits);
     132  	      bits += GMP_NUMB_BITS - 8;
     133  	    }
     134  
     135  	  if (bits != 0)
     136  	    {
     137  	      ASSERT (bp > bp_orig);
     138  	      *--bp = xlimb;
     139  	    }
     140  
     141  	  ASSERT (bp == bp_orig);
     142  	  while (*bp == 0)
     143  	    {
     144  	      bp++;
     145  	      bytes--;
     146  	    }
     147  	}
     148      }
     149  
     150    /* total bytes to be written */
     151    ssize = 4 + bytes;
     152  
     153    /* twos complement negative for the size value */
     154    bytes = (xsize >= 0 ? bytes : -bytes);
     155  
     156    /* so we don't rely on sign extension in ">>" */
     157    ASSERT_ALWAYS (sizeof (bytes) >= 4);
     158  
     159    bp[-4] = bytes >> 24;
     160    bp[-3] = bytes >> 16;
     161    bp[-2] = bytes >> 8;
     162    bp[-1] = bytes;
     163    bp -= 4;
     164  
     165    if (fp == 0)
     166      fp = stdout;
     167    if (fwrite (bp, ssize, 1, fp) != 1)
     168      ssize = 0;
     169  
     170    (*__gmp_free_func) (tp, tsize);
     171    return ssize;
     172  }