1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2006, 2010, 2011 Free Software Foundation, Inc.
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.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "libpspp/integer-format.h"
23 /* Returns true if FORMAT is a valid integer format. */
25 is_integer_format (enum integer_format format)
27 return (format == INTEGER_MSB_FIRST
28 || format == INTEGER_LSB_FIRST
29 || format == INTEGER_VAX);
32 /* Converts the CNT bytes in INTEGER from SRC integer_format to DST
35 integer_convert (enum integer_format src, const void *from,
36 enum integer_format dst, void *to,
40 integer_put (integer_get (src, from, cnt), dst, to, cnt);
42 memcpy (to, from, cnt);
45 /* Returns the value of the CNT-byte integer at FROM, which is in
48 integer_get (enum integer_format format, const void *from_, size_t cnt)
50 const uint8_t *from = from_;
54 assert (is_integer_format (format));
59 case INTEGER_MSB_FIRST:
60 for (i = 0; i < cnt; i++)
61 value = (value << 8) | from[i];
63 case INTEGER_LSB_FIRST:
64 for (i = 0; i < cnt; i++)
65 value = (value << 8) | from[cnt - i - 1];
68 for (i = 0; i < (cnt & ~1); i++)
69 value = (value << 8) | from[i ^ 1];
71 value = (value << 8) | from[cnt - 1];
78 /* Stores VALUE as a CNT-byte integer at TO, in the given
81 integer_put (uint64_t value, enum integer_format format, void *to_, size_t cnt)
86 assert (is_integer_format (format));
89 value <<= 8 * (8 - cnt);
93 case INTEGER_MSB_FIRST:
94 for (i = 0; i < cnt; i++)
100 case INTEGER_LSB_FIRST:
101 for (i = 0; i < cnt; i++)
103 to[cnt - i - 1] = value >> 56;
108 for (i = 0; i < (cnt & ~1); i++)
110 to[i ^ 1] = value >> 56;
114 to[cnt - 1] = value >> 56;
119 /* Returns true if bytes with index IDX1 and IDX2 in VALUE differ
122 bytes_differ (uint64_t value, unsigned int idx1, unsigned int idx2)
124 uint8_t byte1 = value >> (idx1 * 8);
125 uint8_t byte2 = value >> (idx2 * 8);
126 return byte1 != byte2;
129 /* Attempts to identify the integer format in which the LENGTH
130 bytes in INTEGER represent the given EXPECTED_VALUE. Returns
131 true if successful, false otherwise. On success, stores the
132 format in *FORMAT. */
134 integer_identify (uint64_t expected_value, const void *integer, size_t length,
135 enum integer_format *format)
137 /* Odd-length integers are confusing. */
138 assert (length % 2 == 0);
140 /* LENGTH must be greater than 2 because VAX format is
141 equivalent to little-endian for 2-byte integers. */
144 /* EXPECTED_VALUE must contain different byte values, because
145 otherwise all formats are identical. */
146 assert (bytes_differ (expected_value, 0, 1)
147 || bytes_differ (expected_value, 0, 2)
148 || bytes_differ (expected_value, 0, 3)
150 && (bytes_differ (expected_value, 0, 4)
151 || bytes_differ (expected_value, 0, 5)))
153 && (bytes_differ (expected_value, 0, 6)
154 || bytes_differ (expected_value, 0, 7))));
156 if (integer_get (INTEGER_MSB_FIRST, integer, length) == expected_value)
157 *format = INTEGER_MSB_FIRST;
158 else if (integer_get (INTEGER_LSB_FIRST, integer, length) == expected_value)
159 *format = INTEGER_LSB_FIRST;
160 else if (integer_get (INTEGER_VAX, integer, length) == expected_value)
161 *format = INTEGER_VAX;