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