xref: /dragonfly/contrib/gmp/mpz/out_raw.c (revision 479ab7f0)
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