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