github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpz/out_raw.c (about)

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