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