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