Coverage Report

Created: 2025-07-23 06:43

/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
719k
#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
719k
{
52
719k
  mp_size_t  zsize;
53
719k
  mp_ptr     zp;
54
55
719k
  ASSERT (order == 1 || order == -1);
56
719k
  ASSERT (endian == 1 || endian == 0 || endian == -1);
57
719k
  ASSERT (nail <= 8*size);
58
59
719k
  zsize = BITS_TO_LIMBS (count * (8*size - nail));
60
719k
  zp = MPZ_NEWALLOC (z, zsize);
61
62
719k
  if (endian == 0)
63
719k
    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
719k
  if (nail == 0 && GMP_NAIL_BITS == 0
68
719k
      && size == sizeof (mp_limb_t)
69
719k
      && (((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
719k
  else
87
719k
  {
88
719k
    mp_limb_t      limb, byte, wbitsmask;
89
719k
    size_t         i, j, numb, wbytes;
90
719k
    mp_size_t      woffset;
91
719k
    unsigned char  *dp;
92
719k
    int            lbits, wbits;
93
94
719k
    numb = size * 8 - nail;
95
96
    /* whole bytes to process */
97
719k
    wbytes = numb / 8;
98
99
    /* partial byte to process */
100
719k
    wbits = numb % 8;
101
719k
    wbitsmask = (CNST_LIMB(1) << wbits) - 1;
102
103
    /* offset to get to the next word after processing wbytes and wbits */
104
719k
    woffset = (numb + 7) / 8;
105
719k
    woffset = (endian >= 0 ? woffset : -woffset)
106
719k
      + (order < 0 ? size : - (mp_size_t) size);
107
108
    /* least significant byte */
109
719k
    dp = (unsigned char *) data
110
719k
      + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0);
111
112
719k
#define ACCUMULATE(N)                                   \
113
96.8M
    do {                                                \
114
96.8M
      ASSERT (lbits < GMP_NUMB_BITS);                   \
115
96.8M
      ASSERT (limb <= (CNST_LIMB(1) << lbits) - 1);     \
116
96.8M
                                                        \
117
96.8M
      limb |= (mp_limb_t) byte << lbits;                \
118
96.8M
      lbits += (N);                                     \
119
96.8M
      if (lbits >= GMP_NUMB_BITS)                       \
120
96.8M
        {                                               \
121
11.9M
          *zp++ = limb & GMP_NUMB_MASK;                 \
122
11.9M
          lbits -= GMP_NUMB_BITS;                       \
123
11.9M
          ASSERT (lbits < (N));                         \
124
11.9M
          limb = byte >> ((N) - lbits);                 \
125
11.9M
        }                                               \
126
96.8M
    } while (0)
127
128
719k
    limb = 0;
129
719k
    lbits = 0;
130
97.5M
    for (i = 0; i < count; i++)
131
96.8M
      {
132
193M
  for (j = 0; j < wbytes; j++)
133
96.8M
    {
134
96.8M
      byte = *dp;
135
96.8M
      dp -= endian;
136
96.8M
      ACCUMULATE (8);
137
96.8M
    }
138
96.8M
  if (wbits != 0)
139
0
    {
140
0
      byte = *dp & wbitsmask;
141
0
      dp -= endian;
142
0
      ACCUMULATE (wbits);
143
0
    }
144
96.8M
  dp += woffset;
145
96.8M
      }
146
147
719k
    if (lbits != 0)
148
449k
      {
149
449k
  ASSERT (lbits <= GMP_NUMB_BITS);
150
449k
  ASSERT_LIMB (limb);
151
449k
  *zp++ = limb;
152
449k
      }
153
154
719k
    ASSERT (zp == PTR(z) + zsize);
155
156
    /* low byte of word after most significant */
157
719k
    ASSERT (dp == (unsigned char *) data
158
719k
      + (order < 0 ? count*size : - (mp_size_t) size)
159
719k
      + (endian >= 0 ? (mp_size_t) size - 1 : 0));
160
161
719k
  }
162
163
719k
  zp = PTR(z);
164
719k
  MPN_NORMALIZE (zp, zsize);
165
719k
  SIZ(z) = zsize;
166
719k
}