Home | History | Annotate | Line # | Download | only in mpz
out_raw.c revision 1.1.1.3
      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 }
    174