Coverage Report

Created: 2026-11-12 07:00

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