1/* Test mpz_inp_raw and mpz_out_raw.
2
3Copyright 2001 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
19
20#include "config.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#if HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28
29#include "gmp-impl.h"
30#include "tests.h"
31
32#define FILENAME  "t-io_raw.tmp"
33
34
35/* In the fopen, "b" selects binary mode on DOS systems, meaning no
36   conversion of '\n' to and from CRLF.  It's believed systems without such
37   nonsense will simply ignore the "b", but in case that's not so a plain
38   "w+" is attempted if "w+b" fails.  */
39
40FILE *
41fopen_wplusb_or_die (const char *filename)
42{
43  FILE  *fp;
44  fp = fopen (filename, "w+b");
45  if (fp == NULL)
46    fp = fopen (filename, "w+");
47
48  if (fp == NULL)
49    {
50      printf ("Cannot create file %s\n", filename);
51      abort ();
52    }
53  return fp;
54}
55
56/* use 0x80 to check nothing bad happens with sign extension etc */
57#define BYTEVAL(i)  (((i) + 1) | 0x80)
58
59void
60check_in (void)
61{
62  int        i, j, zeros, neg, error = 0;
63  mpz_t      want, got;
64  size_t     want_ret, got_ret;
65  mp_size_t  size;
66  FILE       *fp;
67
68  mpz_init (want);
69  mpz_init (got);
70
71  for (i = 0; i < 32; i++)
72    {
73      for (zeros = 0; zeros < 8; zeros++)
74	{
75	  for (neg = 0; neg <= 1; neg++)
76	    {
77	      want_ret = i + zeros + 4;
78
79	      /* need this to get the twos complement right */
80	      ASSERT_ALWAYS (sizeof (size) >= 4);
81
82	      size = i + zeros;
83	      if (neg)
84		size = -size;
85
86	      fp = fopen_wplusb_or_die (FILENAME);
87	      for (j = 3; j >= 0; j--)
88		ASSERT_ALWAYS (putc ((size >> (j*8)) & 0xFF, fp) != EOF);
89	      for (j = 0; j < zeros; j++)
90		ASSERT_ALWAYS (putc ('\0', fp) != EOF);
91	      for (j = 0; j < i; j++)
92		ASSERT_ALWAYS (putc (BYTEVAL (j), fp) != EOF);
93	      /* and some trailing garbage */
94	      ASSERT_ALWAYS (putc ('x', fp) != EOF);
95	      ASSERT_ALWAYS (putc ('y', fp) != EOF);
96	      ASSERT_ALWAYS (putc ('z', fp) != EOF);
97	      ASSERT_ALWAYS (fflush (fp) == 0);
98	      rewind (fp);
99
100	      got_ret = mpz_inp_raw (got, fp);
101	      ASSERT_ALWAYS (! ferror(fp));
102	      ASSERT_ALWAYS (fclose (fp) == 0);
103
104	      MPZ_CHECK_FORMAT (got);
105
106	      if (got_ret != want_ret)
107		{
108		  printf ("check_in: return value wrong\n");
109		  error = 1;
110		}
111	      if (mpz_cmp (got, want) != 0)
112		{
113		  printf ("check_in: result wrong\n");
114		  error = 1;
115		}
116	      if (error)
117		{
118		  printf    ("  i=%d zeros=%d neg=%d\n", i, zeros, neg);
119		  printf    ("  got_ret  %lu\n", (unsigned long) got_ret);
120		  printf    ("  want_ret %lu\n", (unsigned long) want_ret);
121		  mpz_trace ("  got      ", got);
122		  mpz_trace ("  want     ", want);
123		  abort ();
124		}
125
126	      mpz_neg (want, want);
127	    }
128	}
129      mpz_mul_2exp (want, want, 8);
130      mpz_add_ui (want, want, (unsigned long) BYTEVAL (i));
131    }
132
133  mpz_clear (want);
134  mpz_clear (got);
135}
136
137
138void
139check_out (void)
140{
141  int        i, j, neg, error = 0;
142  mpz_t      z;
143  char       want[256], got[256], *p;
144  size_t     want_len, got_ret, got_read;
145  mp_size_t  size;
146  FILE       *fp;
147
148  mpz_init (z);
149
150  for (i = 0; i < 32; i++)
151    {
152      for (neg = 0; neg <= 1; neg++)
153	{
154	  want_len = i + 4;
155
156	  /* need this to get the twos complement right */
157	  ASSERT_ALWAYS (sizeof (size) >= 4);
158
159	  size = i;
160	  if (neg)
161	    size = -size;
162
163	  p = want;
164	  for (j = 3; j >= 0; j--)
165	    *p++ = size >> (j*8);
166	  for (j = 0; j < i; j++)
167	    *p++ = BYTEVAL (j);
168	  ASSERT_ALWAYS (p <= want + sizeof (want));
169
170	  fp = fopen_wplusb_or_die (FILENAME);
171	  got_ret = mpz_out_raw (fp, z);
172	  ASSERT_ALWAYS (fflush (fp) == 0);
173	  rewind (fp);
174	  got_read = fread (got, 1, sizeof(got), fp);
175	  ASSERT_ALWAYS (! ferror(fp));
176	  ASSERT_ALWAYS (fclose (fp) == 0);
177
178	  if (got_ret != want_len)
179	    {
180	      printf ("check_out: wrong return value\n");
181	      error = 1;
182	    }
183	  if (got_read != want_len)
184	    {
185	      printf ("check_out: wrong number of bytes read back\n");
186	      error = 1;
187	    }
188	  if (memcmp (want, got, want_len) != 0)
189	    {
190	      printf ("check_out: wrong data\n");
191	      error = 1;
192	    }
193	  if (error)
194	    {
195	      printf    ("  i=%d neg=%d\n", i, neg);
196	      mpz_trace ("  z", z);
197	      printf    ("  got_ret  %lu\n", (unsigned long) got_ret);
198	      printf    ("  got_read %lu\n", (unsigned long) got_read);
199	      printf    ("  want_len %lu\n", (unsigned long) want_len);
200	      printf    ("  want");
201	      for (j = 0; j < want_len; j++)
202		printf (" %02X", (unsigned) (unsigned char) want[j]);
203	      printf    ("\n");
204	      printf    ("  got ");
205	      for (j = 0; j < want_len; j++)
206		printf (" %02X", (unsigned) (unsigned char) got[j]);
207	      printf    ("\n");
208	      abort ();
209	    }
210
211	  mpz_neg (z, z);
212	}
213      mpz_mul_2exp (z, z, 8);
214      mpz_add_ui (z, z, (unsigned long) BYTEVAL (i));
215    }
216
217  mpz_clear (z);
218}
219
220
221void
222check_rand (void)
223{
224  gmp_randstate_ptr  rands = RANDS;
225  int        i, error = 0;
226  mpz_t      got, want;
227  size_t     inp_ret, out_ret;
228  FILE       *fp;
229
230  mpz_init (want);
231  mpz_init (got);
232
233  for (i = 0; i < 500; i++)
234    {
235      mpz_erandomb (want, rands, 10*GMP_LIMB_BITS);
236      mpz_negrandom (want, rands);
237
238      fp = fopen_wplusb_or_die (FILENAME);
239      out_ret = mpz_out_raw (fp, want);
240      ASSERT_ALWAYS (fflush (fp) == 0);
241      rewind (fp);
242      inp_ret = mpz_inp_raw (got, fp);
243      ASSERT_ALWAYS (fclose (fp) == 0);
244
245      MPZ_CHECK_FORMAT (got);
246
247      if (inp_ret != out_ret)
248	{
249	  printf ("check_rand: different inp/out return values\n");
250	  error = 1;
251	}
252      if (mpz_cmp (got, want) != 0)
253	{
254	  printf ("check_rand: wrong result\n");
255	  error = 1;
256	}
257      if (error)
258	{
259	  printf    ("  out_ret %lu\n", (unsigned long) out_ret);
260	  printf    ("  inp_ret %lu\n", (unsigned long) inp_ret);
261	  mpz_trace ("  want", want);
262	  mpz_trace ("  got ", got);
263	  abort ();
264	}
265    }
266
267  mpz_clear (got);
268  mpz_clear (want);
269}
270
271
272int
273main (void)
274{
275  tests_start ();
276  mp_trace_base = -16;
277
278  check_in ();
279  check_out ();
280  check_rand ();
281
282  unlink (FILENAME);
283  tests_end ();
284
285  exit (0);
286}
287