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