Coverage Report

Created: 2025-03-18 06:55

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