1 /* word_io.c -- word oriented I/O
2 Copyright (C) 2007-2022 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 /* config.h must be included first. */
19 #include <config.h>
20
21 /* system headers. */
22 #include <errno.h>
23 #include <stdbool.h> /* for bool */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 /* gnulib headers. */
29 #include "byteswap.h"
30 #include "error.h"
31 #include "quotearg.h"
32
33 /* find headers. */
34 #include "system.h"
35 #include "die.h"
36 #include "locatedb.h"
37
38
39 enum { WORDBYTES=4 };
40
41 static int
42 decode_value (const unsigned char data[],
43 int limit,
44 GetwordEndianState *endian_state_flag,
45 const char *filename)
46 {
47 int swapped;
48 union
49 {
50 int ival; /* native representation */
51 unsigned char data[WORDBYTES];
52 } u;
53 u.ival = 0;
54 memcpy (&u.data, data, WORDBYTES);
55 swapped = bswap_32(u.ival); /* byteswapped */
56
57 if (*endian_state_flag == GetwordEndianStateInitial)
58 {
59 if (u.ival <= limit)
60 {
61 if (swapped > limit)
62 {
63 /* the native value is inside the limit and the
64 * swapped value is not. We take this as proof
65 * that we should be using the native byte order.
66 */
67 *endian_state_flag = GetwordEndianStateNative;
68 }
69 return u.ival;
70 }
71 else
72 {
73 if (swapped <= limit)
74 {
75 /* Aha, now we know we have to byte-swap. */
76 error (0, 0,
77 _("WARNING: locate database %s was "
78 "built with a different byte order"),
79 quotearg_n_style (0, locale_quoting_style, filename));
80 *endian_state_flag = GetwordEndianStateSwab;
81 return swapped;
82 }
83 else
84 {
85 /* u.ival > limit and swapped > limit. For the moment, assume
86 * native ordering.
87 */
88 return u.ival;
89 }
90 }
91 }
92 else
93 {
94 /* We already know the byte order. */
95 if (*endian_state_flag == GetwordEndianStateSwab)
96 return swapped;
97 else
98 return u.ival;
99 }
100 }
101
102
103
104 int
105 getword (FILE *fp,
106 const char *filename,
107 size_t maxvalue,
108 GetwordEndianState *endian_state_flag)
109 {
110 unsigned char data[4];
111 size_t bytes_read;
112
113 clearerr (fp);
114 bytes_read = fread (data, WORDBYTES, 1, fp);
115 if (bytes_read != 1)
116 {
117 const char * quoted_name = quotearg_n_style (0, locale_quoting_style,
118 filename);
119 /* Distinguish between a truncated database and an I/O error.
120 * Either condition is fatal.
121 */
122 if (feof (fp))
123 die (EXIT_FAILURE, 0, _("unexpected EOF in %s"), quoted_name);
124 else
125 die (EXIT_FAILURE, errno,
126 _("error reading a word from %s"), quoted_name);
127 abort ();
128 }
129 else
130 {
131 return decode_value (data, maxvalue, endian_state_flag, filename);
132 }
133 }