Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / contrib / gmp / mpz / export.c
1 /* mpz_export -- create word data from mpz.
2
3 Copyright 2002, 2003 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>  /* for NULL */
21 #include "gmp.h"
22 #include "gmp-impl.h"
23 #include "longlong.h"
24
25
26 #if HAVE_LIMB_BIG_ENDIAN
27 #define HOST_ENDIAN     1
28 #endif
29 #if HAVE_LIMB_LITTLE_ENDIAN
30 #define HOST_ENDIAN     (-1)
31 #endif
32 #ifndef HOST_ENDIAN
33 static const mp_limb_t  endian_test = (CNST_LIMB(1) << (GMP_LIMB_BITS-7)) - 1;
34 #define HOST_ENDIAN     (* (signed char *) &endian_test)
35 #endif
36
37
38 #define MPN_SIZEINBASE_2EXP(result, ptr, size, base2exp)                \
39   do {                                                                  \
40     int            __cnt;                                               \
41     unsigned long  __totbits;                                           \
42     ASSERT ((size) > 0);                                                \
43     ASSERT ((ptr)[(size)-1] != 0);                                      \
44     count_leading_zeros (__cnt, (ptr)[(size)-1]);                       \
45     __totbits = (size) * GMP_NUMB_BITS - (__cnt - GMP_NAIL_BITS);       \
46     (result) = (__totbits + (base2exp)-1) / (base2exp);                 \
47   } while (0)
48
49
50 void *
51 mpz_export (void *data, size_t *countp, int order,
52             size_t size, int endian, size_t nail, mpz_srcptr z)
53 {
54   mp_size_t      zsize;
55   mp_srcptr      zp;
56   size_t         count, dummy;
57   unsigned long  numb;
58   unsigned       align;
59
60   ASSERT (order == 1 || order == -1);
61   ASSERT (endian == 1 || endian == 0 || endian == -1);
62   ASSERT (nail <= 8*size);
63   ASSERT (8*size-nail > 0);
64
65   if (countp == NULL)
66     countp = &dummy;
67
68   zsize = SIZ(z);
69   if (zsize == 0)
70     {
71       *countp = 0;
72       return data;
73     }
74
75   zsize = ABS (zsize);
76   zp = PTR(z);
77   numb = 8*size - nail;
78   MPN_SIZEINBASE_2EXP (count, zp, zsize, numb);
79   *countp = count;
80
81   if (data == NULL)
82     data = (*__gmp_allocate_func) (count*size);
83
84   if (endian == 0)
85     endian = HOST_ENDIAN;
86
87   align = ((char *) data - (char *) NULL) % sizeof (mp_limb_t);
88
89   if (nail == GMP_NAIL_BITS)
90     {
91       if (size == sizeof (mp_limb_t) && align == 0)
92         {
93           if (order == -1 && endian == HOST_ENDIAN)
94             {
95               MPN_COPY ((mp_ptr) data, zp, (mp_size_t) count);
96               return data;
97             }
98           if (order == 1 && endian == HOST_ENDIAN)
99             {
100               MPN_REVERSE ((mp_ptr) data, zp, (mp_size_t) count);
101               return data;
102             }
103
104           if (order == -1 && endian == -HOST_ENDIAN)
105             {
106               MPN_BSWAP ((mp_ptr) data, zp, (mp_size_t) count);
107               return data;
108             }
109           if (order == 1 && endian == -HOST_ENDIAN)
110             {
111               MPN_BSWAP_REVERSE ((mp_ptr) data, zp, (mp_size_t) count);
112               return data;
113             }
114         }
115     }
116
117   {
118     mp_limb_t      limb, wbitsmask;
119     size_t         i, numb;
120     mp_size_t      j, wbytes, woffset;
121     unsigned char  *dp;
122     int            lbits, wbits;
123     mp_srcptr      zend;
124
125     numb = size * 8 - nail;
126
127     /* whole bytes per word */
128     wbytes = numb / 8;
129
130     /* possible partial byte */
131     wbits = numb % 8;
132     wbitsmask = (CNST_LIMB(1) << wbits) - 1;
133
134     /* offset to get to the next word */
135     woffset = (endian >= 0 ? size : - (mp_size_t) size)
136       + (order < 0 ? size : - (mp_size_t) size);
137
138     /* least significant byte */
139     dp = (unsigned char *) data
140       + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0);
141
142 #define EXTRACT(N, MASK)                                \
143     do {                                                \
144       if (lbits >= (N))                                 \
145         {                                               \
146           *dp = limb MASK;                              \
147           limb >>= (N);                                 \
148           lbits -= (N);                                 \
149         }                                               \
150       else                                              \
151         {                                               \
152           mp_limb_t  newlimb;                           \
153           newlimb = (zp == zend ? 0 : *zp++);           \
154           *dp = (limb | (newlimb << lbits)) MASK;       \
155           limb = newlimb >> ((N)-lbits);                \
156           lbits += GMP_NUMB_BITS - (N);                 \
157         }                                               \
158     } while (0)
159
160     zend = zp + zsize;
161     lbits = 0;
162     limb = 0;
163     for (i = 0; i < count; i++)
164       {
165         for (j = 0; j < wbytes; j++)
166           {
167             EXTRACT (8, + 0);
168             dp -= endian;
169           }
170         if (wbits != 0)
171           {
172             EXTRACT (wbits, & wbitsmask);
173             dp -= endian;
174             j++;
175           }
176         for ( ; j < size; j++)
177           {
178             *dp = '\0';
179             dp -= endian;
180           }
181         dp += woffset;
182       }
183
184     ASSERT (zp == PTR(z) + ABSIZ(z));
185
186     /* low byte of word after most significant */
187     ASSERT (dp == (unsigned char *) data
188             + (order < 0 ? count*size : - (mp_size_t) size)
189             + (endian >= 0 ? (mp_size_t) size - 1 : 0));
190   }
191   return data;
192 }