xref: /netbsd-src/external/lgpl3/gmp/dist/mpz/out_raw.c (revision c34236556bea94afcaca1782d7d228301edc3ea0)
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