xref: /dragonfly/contrib/gmp/mpz/import.c (revision d4ef6694)
1 /* mpz_import -- set mpz from word data.
2 
3 Copyright 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 
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 void
39 mpz_import (mpz_ptr z, size_t count, int order,
40             size_t size, int endian, size_t nail, const void *data)
41 {
42   mp_size_t  zsize;
43   mp_ptr     zp;
44 
45   ASSERT (order == 1 || order == -1);
46   ASSERT (endian == 1 || endian == 0 || endian == -1);
47   ASSERT (nail <= 8*size);
48 
49   zsize = (count * (8*size - nail) + GMP_NUMB_BITS-1) / GMP_NUMB_BITS;
50   MPZ_REALLOC (z, zsize);
51   zp = PTR(z);
52 
53   if (endian == 0)
54     endian = HOST_ENDIAN;
55 
56   /* Can't use these special cases with nails currently, since they don't
57      mask out the nail bits in the input data.  */
58   if (nail == 0 && GMP_NAIL_BITS == 0)
59     {
60       unsigned  align = ((char *) data - (char *) NULL) % sizeof (mp_limb_t);
61 
62       if (order == -1
63           && size == sizeof (mp_limb_t)
64           && endian == HOST_ENDIAN
65           && align == 0)
66         {
67           MPN_COPY (zp, (mp_srcptr) data, (mp_size_t) count);
68           goto done;
69         }
70 
71       if (order == -1
72           && size == sizeof (mp_limb_t)
73           && endian == - HOST_ENDIAN
74           && align == 0)
75         {
76           MPN_BSWAP (zp, (mp_srcptr) data, (mp_size_t) count);
77           goto done;
78         }
79 
80       if (order == 1
81           && size == sizeof (mp_limb_t)
82           && endian == HOST_ENDIAN
83           && align == 0)
84         {
85           MPN_REVERSE (zp, (mp_srcptr) data, (mp_size_t) count);
86           goto done;
87         }
88     }
89 
90   {
91     mp_limb_t      limb, byte, wbitsmask;
92     size_t         i, j, numb, wbytes;
93     mp_size_t      woffset;
94     unsigned char  *dp;
95     int            lbits, wbits;
96 
97     numb = size * 8 - nail;
98 
99     /* whole bytes to process */
100     wbytes = numb / 8;
101 
102     /* partial byte to process */
103     wbits = numb % 8;
104     wbitsmask = (CNST_LIMB(1) << wbits) - 1;
105 
106     /* offset to get to the next word after processing wbytes and wbits */
107     woffset = (numb + 7) / 8;
108     woffset = (endian >= 0 ? woffset : -woffset)
109       + (order < 0 ? size : - (mp_size_t) size);
110 
111     /* least significant byte */
112     dp = (unsigned char *) data
113       + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0);
114 
115 #define ACCUMULATE(N)                                   \
116     do {                                                \
117       ASSERT (lbits < GMP_NUMB_BITS);                   \
118       ASSERT (limb <= (CNST_LIMB(1) << lbits) - 1);     \
119                                                         \
120       limb |= (mp_limb_t) byte << lbits;                \
121       lbits += (N);                                     \
122       if (lbits >= GMP_NUMB_BITS)                       \
123         {                                               \
124           *zp++ = limb & GMP_NUMB_MASK;                 \
125           lbits -= GMP_NUMB_BITS;                       \
126           ASSERT (lbits < (N));                         \
127           limb = byte >> ((N) - lbits);                 \
128         }                                               \
129     } while (0)
130 
131     limb = 0;
132     lbits = 0;
133     for (i = 0; i < count; i++)
134       {
135         for (j = 0; j < wbytes; j++)
136           {
137             byte = *dp;
138             dp -= endian;
139             ACCUMULATE (8);
140           }
141         if (wbits != 0)
142           {
143             byte = *dp & wbitsmask;
144             dp -= endian;
145             ACCUMULATE (wbits);
146           }
147         dp += woffset;
148       }
149 
150     if (lbits != 0)
151       {
152         ASSERT (lbits <= GMP_NUMB_BITS);
153         ASSERT_LIMB (limb);
154         *zp++ = limb;
155       }
156 
157     ASSERT (zp == PTR(z) + zsize);
158 
159     /* low byte of word after most significant */
160     ASSERT (dp == (unsigned char *) data
161             + (order < 0 ? count*size : - (mp_size_t) size)
162             + (endian >= 0 ? (mp_size_t) size - 1 : 0));
163 
164   }
165 
166  done:
167   zp = PTR(z);
168   MPN_NORMALIZE (zp, zsize);
169   SIZ(z) = zsize;
170 }
171