Coverage Report

Created: 2024-11-25 06:29

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