xref: /netbsd/external/lgpl3/gmp/dist/mpz/out_raw.c (revision 671ea119)
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-impl.h"
33 #include "longlong.h"
34 
35 
36 /* HTON_LIMB_STORE takes a normal host byte order limb and stores it as
37    network byte order (ie. big endian). */
38 
39 #if HAVE_LIMB_BIG_ENDIAN
40 #define HTON_LIMB_STORE(dst, limb)  do { *(dst) = (limb); } while (0)
41 #endif
42 
43 #if HAVE_LIMB_LITTLE_ENDIAN
44 #define HTON_LIMB_STORE(dst, limb)  BSWAP_LIMB_STORE (dst, limb)
45 #endif
46 
47 #ifndef HTON_LIMB_STORE
48 #define HTON_LIMB_STORE(dst, limb)                                      \
49   do {                                                                  \
50     mp_limb_t  __limb = (limb);                                         \
51     char      *__p = (char *) (dst);                                    \
52     int        __i;                                                     \
53     for (__i = 0; __i < GMP_LIMB_BYTES; __i++)                       \
54       __p[__i] = (char) (__limb >> ((GMP_LIMB_BYTES-1 - __i) * 8));  \
55   } while (0)
56 #endif
57 
58 
59 size_t
mpz_out_raw(FILE * fp,mpz_srcptr x)60 mpz_out_raw (FILE *fp, mpz_srcptr x)
61 {
62   mp_size_t   xsize, abs_xsize, bytes, i;
63   mp_srcptr   xp;
64   char        *tp, *bp;
65   mp_limb_t   xlimb;
66   int         zeros;
67   size_t      tsize, ssize;
68 
69   xsize = SIZ(x);
70   abs_xsize = ABS (xsize);
71   bytes = (abs_xsize * GMP_NUMB_BITS + 7) / 8;
72   tsize = ROUND_UP_MULTIPLE ((unsigned) 4, GMP_LIMB_BYTES) + bytes;
73 
74   tp = __GMP_ALLOCATE_FUNC_TYPE (tsize, char);
75   bp = tp + ROUND_UP_MULTIPLE ((unsigned) 4, GMP_LIMB_BYTES);
76 
77   if (bytes != 0)
78     {
79       bp += bytes;
80       xp = PTR (x);
81       i = abs_xsize;
82 
83       if (GMP_NAIL_BITS == 0)
84 	{
85 	  /* reverse limb order, and byte swap if necessary */
86 #ifdef _CRAY
87 	  _Pragma ("_CRI ivdep");
88 #endif
89 	  do
90 	    {
91 	      bp -= GMP_LIMB_BYTES;
92 	      xlimb = *xp;
93 	      HTON_LIMB_STORE ((mp_ptr) bp, xlimb);
94 	      xp++;
95 	    }
96 	  while (--i > 0);
97 
98 	  /* strip high zero bytes (without fetching from bp) */
99 	  count_leading_zeros (zeros, xlimb);
100 	  zeros /= 8;
101 	  bp += zeros;
102 	  bytes -= zeros;
103 	}
104       else
105 	{
106 	  mp_limb_t  new_xlimb;
107 	  int        bits;
108 	  ASSERT_CODE (char *bp_orig = bp - bytes);
109 
110 	  ASSERT_ALWAYS (GMP_NUMB_BITS >= 8);
111 
112 	  bits = 0;
113 	  xlimb = 0;
114 	  for (;;)
115 	    {
116 	      while (bits >= 8)
117 		{
118 		  ASSERT (bp > bp_orig);
119 		  *--bp = xlimb & 0xFF;
120 		  xlimb >>= 8;
121 		  bits -= 8;
122 		}
123 
124 	      if (i == 0)
125 		break;
126 
127 	      new_xlimb = *xp++;
128 	      i--;
129 	      ASSERT (bp > bp_orig);
130 	      *--bp = (xlimb | (new_xlimb << bits)) & 0xFF;
131 	      xlimb = new_xlimb >> (8 - bits);
132 	      bits += GMP_NUMB_BITS - 8;
133 	    }
134 
135 	  if (bits != 0)
136 	    {
137 	      ASSERT (bp > bp_orig);
138 	      *--bp = xlimb;
139 	    }
140 
141 	  ASSERT (bp == bp_orig);
142 	  while (*bp == 0)
143 	    {
144 	      bp++;
145 	      bytes--;
146 	    }
147 	}
148     }
149 
150   /* total bytes to be written */
151   ssize = 4 + bytes;
152 
153   /* twos complement negative for the size value */
154   bytes = (xsize >= 0 ? bytes : -bytes);
155 
156   /* so we don't rely on sign extension in ">>" */
157   ASSERT_ALWAYS (sizeof (bytes) >= 4);
158 
159   bp[-4] = bytes >> 24;
160   bp[-3] = bytes >> 16;
161   bp[-2] = bytes >> 8;
162   bp[-1] = bytes;
163   bp -= 4;
164 
165   if (fp == 0)
166     fp = stdout;
167   if (fwrite (bp, ssize, 1, fp) != 1)
168     ssize = 0;
169 
170   (*__gmp_free_func) (tp, tsize);
171   return ssize;
172 }
173