1 /* PSPP - computes sample statistics.
2 Copyright (C) 2006 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 #include <libpspp/integer-format.h>
26 /* Returns true if FORMAT is a valid integer format. */
28 is_integer_format (enum integer_format format)
30 return (format == INTEGER_MSB_FIRST
31 || format == INTEGER_LSB_FIRST
32 || format == INTEGER_VAX);
35 /* Converts the CNT bytes in INTEGER from SRC integer_format to DST
38 integer_convert (enum integer_format src, const void *from,
39 enum integer_format dst, void *to,
43 integer_put (integer_get (src, from, cnt), dst, to, cnt);
45 memcpy (to, from, cnt);
48 /* Returns the value of the CNT-byte integer at FROM, which is in
51 integer_get (enum integer_format format, const void *from_, size_t cnt)
53 const uint8_t *from = from_;
57 assert (is_integer_format (format));
62 case INTEGER_MSB_FIRST:
63 for (i = 0; i < cnt; i++)
64 value = (value << 8) | from[i];
66 case INTEGER_LSB_FIRST:
67 for (i = 0; i < cnt; i++)
68 value = (value << 8) | from[cnt - i - 1];
71 for (i = 0; i < (cnt & ~1); i++)
72 value = (value << 8) | from[i ^ 1];
74 value = (value << 8) | from[cnt - 1];
81 /* Stores VALUE as a CNT-byte integer at TO, in the given
84 integer_put (uint64_t value, enum integer_format format, void *to_, size_t cnt)
89 assert (is_integer_format (format));
92 value <<= 8 * (8 - cnt);
96 case INTEGER_MSB_FIRST:
97 for (i = 0; i < cnt; i++)
103 case INTEGER_LSB_FIRST:
104 for (i = 0; i < cnt; i++)
106 to[cnt - i - 1] = value >> 56;
111 for (i = 0; i < (cnt & ~1); i++)
113 to[i ^ 1] = value >> 56;
117 to[cnt - 1] = value >> 56;
122 /* Returns true if bytes with index IDX1 and IDX2 in VALUE differ
125 bytes_differ (uint64_t value, unsigned int idx1, unsigned int idx2)
127 uint8_t byte1 = value >> (idx1 * 8);
128 uint8_t byte2 = value >> (idx2 * 8);
129 return byte1 != byte2;
132 /* Attempts to identify the integer format in which the LENGTH
133 bytes in INTEGER represent the given EXPECTED_VALUE. Returns
134 true if successful, false otherwise. On success, stores the
135 format in *FORMAT. */
137 integer_identify (uint64_t expected_value, const void *integer, size_t length,
138 enum integer_format *format)
140 /* Odd-length integers are confusing. */
141 assert (length % 2 == 0);
143 /* LENGTH must be greater than 2 because VAX format is
144 equivalent to little-endian for 2-byte integers. */
147 /* EXPECTED_VALUE must contain different byte values, because
148 otherwise all formats are identical. */
149 assert (bytes_differ (expected_value, 0, 1)
150 || bytes_differ (expected_value, 0, 2)
151 || bytes_differ (expected_value, 0, 3)
153 && (bytes_differ (expected_value, 0, 4)
154 || bytes_differ (expected_value, 0, 5)))
156 && (bytes_differ (expected_value, 0, 6)
157 || bytes_differ (expected_value, 0, 7))));
159 if (integer_get (INTEGER_MSB_FIRST, integer, length) == expected_value)
160 *format = INTEGER_MSB_FIRST;
161 else if (integer_get (INTEGER_LSB_FIRST, integer, length) == expected_value)
162 *format = INTEGER_LSB_FIRST;
163 else if (integer_get (INTEGER_VAX, integer, length) == expected_value)
164 *format = INTEGER_VAX;