Tizen 2.1 base
[external/gmp.git] / mpz / out_raw.c
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 }