Coverage Report

Created: 2024-11-25 06:27

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