Home | History | Annotate | Line # | Download | only in mpz
out_raw.c revision 1.1.1.2
      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 the GNU Lesser General Public License as published by
      9 the Free Software Foundation; either version 3 of the License, or (at your
     10 option) any later version.
     11 
     12 The GNU MP Library is distributed in the hope that it will be useful, but
     13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     14 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
     15 License for more details.
     16 
     17 You should have received a copy of the GNU Lesser General Public License
     18 along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
     19 
     20 #include <stdio.h>
     21 #include "gmp.h"
     22 #include "gmp-impl.h"
     23 #include "longlong.h"
     24 
     25 
     26 /* HTON_LIMB_STORE takes a normal host byte order limb and stores it as
     27    network byte order (ie. big endian). */
     28 
     29 #if HAVE_LIMB_BIG_ENDIAN
     30 #define HTON_LIMB_STORE(dst, limb)  do { *(dst) = (limb); } while (0)
     31 #endif
     32 
     33 #if HAVE_LIMB_LITTLE_ENDIAN
     34 #define HTON_LIMB_STORE(dst, limb)  BSWAP_LIMB_STORE (dst, limb)
     35 #endif
     36 
     37 #ifndef HTON_LIMB_STORE
     38 #define HTON_LIMB_STORE(dst, limb)                                      \
     39   do {                                                                  \
     40     mp_limb_t  __limb = (limb);                                         \
     41     char      *__p = (char *) (dst);                                    \
     42     int        __i;                                                     \
     43     for (__i = 0; __i < BYTES_PER_MP_LIMB; __i++)                       \
     44       __p[__i] = (char) (__limb >> ((BYTES_PER_MP_LIMB-1 - __i) * 8));  \
     45   } while (0)
     46 #endif
     47 
     48 
     49 size_t
     50 mpz_out_raw (FILE *fp, mpz_srcptr x)
     51 {
     52   mp_size_t   xsize, abs_xsize, bytes, i;
     53   mp_srcptr   xp;
     54   char        *tp, *bp;
     55   mp_limb_t   xlimb;
     56   int         zeros;
     57   size_t      tsize, ssize;
     58 
     59   xsize = SIZ(x);
     60   abs_xsize = ABS (xsize);
     61   bytes = (abs_xsize * GMP_NUMB_BITS + 7) / 8;
     62   tsize = ROUND_UP_MULTIPLE ((unsigned) 4, BYTES_PER_MP_LIMB) + bytes;
     63 
     64   tp = __GMP_ALLOCATE_FUNC_TYPE (tsize, char);
     65   bp = tp + ROUND_UP_MULTIPLE ((unsigned) 4, BYTES_PER_MP_LIMB);
     66 
     67   if (bytes != 0)
     68     {
     69       bp += bytes;
     70       xp = PTR (x);
     71       i = abs_xsize;
     72 
     73       if (GMP_NAIL_BITS == 0)
     74 	{
     75 	  /* reverse limb order, and byte swap if necessary */
     76 #ifdef _CRAY
     77 	  _Pragma ("_CRI ivdep");
     78 #endif
     79 	  do
     80 	    {
     81 	      bp -= BYTES_PER_MP_LIMB;
     82 	      xlimb = *xp;
     83 	      HTON_LIMB_STORE ((mp_ptr) bp, xlimb);
     84 	      xp++;
     85 	    }
     86 	  while (--i > 0);
     87 
     88 	  /* strip high zero bytes (without fetching from bp) */
     89 	  count_leading_zeros (zeros, xlimb);
     90 	  zeros /= 8;
     91 	  bp += zeros;
     92 	  bytes -= zeros;
     93 	}
     94       else
     95 	{
     96 	  mp_limb_t  new_xlimb;
     97 	  int        bits;
     98 	  ASSERT_CODE (char *bp_orig = bp - bytes);
     99 
    100 	  ASSERT_ALWAYS (GMP_NUMB_BITS >= 8);
    101 
    102 	  bits = 0;
    103 	  xlimb = 0;
    104 	  for (;;)
    105 	    {
    106 	      while (bits >= 8)
    107 		{
    108 		  ASSERT (bp > bp_orig);
    109 		  *--bp = xlimb & 0xFF;
    110 		  xlimb >>= 8;
    111 		  bits -= 8;
    112 		}
    113 
    114 	      if (i == 0)
    115 		break;
    116 
    117 	      new_xlimb = *xp++;
    118 	      i--;
    119 	      ASSERT (bp > bp_orig);
    120 	      *--bp = (xlimb | (new_xlimb << bits)) & 0xFF;
    121 	      xlimb = new_xlimb >> (8 - bits);
    122 	      bits += GMP_NUMB_BITS - 8;
    123 	    }
    124 
    125 	  if (bits != 0)
    126 	    {
    127 	      ASSERT (bp > bp_orig);
    128 	      *--bp = xlimb;
    129 	    }
    130 
    131 	  ASSERT (bp == bp_orig);
    132 	  while (*bp == 0)
    133 	    {
    134 	      bp++;
    135 	      bytes--;
    136 	    }
    137 	}
    138     }
    139 
    140   /* total bytes to be written */
    141   ssize = 4 + bytes;
    142 
    143   /* twos complement negative for the size value */
    144   bytes = (xsize >= 0 ? bytes : -bytes);
    145 
    146   /* so we don't rely on sign extension in ">>" */
    147   ASSERT_ALWAYS (sizeof (bytes) >= 4);
    148 
    149   bp[-4] = bytes >> 24;
    150   bp[-3] = bytes >> 16;
    151   bp[-2] = bytes >> 8;
    152   bp[-1] = bytes;
    153   bp -= 4;
    154 
    155   if (fp == 0)
    156     fp = stdout;
    157   if (fwrite (bp, ssize, 1, fp) != 1)
    158     ssize = 0;
    159 
    160   (*__gmp_free_func) (tp, tsize);
    161   return ssize;
    162 }
    163