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 *
mpz_export(void * data,size_t * countp,int order,size_t size,int endian,size_t nail,mpz_srcptr z)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 }
193