1 /* PSPP - computes sample statistics.
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 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, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include <libpspp/integer-format.h>
25 /* Returns true if FORMAT is a valid integer format. */
27 is_integer_format (enum integer_format format)
29 return (format == INTEGER_MSB_FIRST
30 || format == INTEGER_LSB_FIRST
31 || format == INTEGER_VAX);
34 /* Converts the CNT bytes in INTEGER from SRC integer_format to DST
37 integer_convert (enum integer_format src, const void *from,
38 enum integer_format dst, void *to,
42 integer_put (integer_get (src, from, cnt), dst, to, cnt);
44 memcpy (to, from, cnt);
47 /* Returns the value of the CNT-byte integer at FROM, which is in
50 integer_get (enum integer_format format, const void *from_, size_t cnt)
52 const uint8_t *from = from_;
56 assert (is_integer_format (format));
61 case INTEGER_MSB_FIRST:
62 for (i = 0; i < cnt; i++)
63 value = (value << 8) | from[i];
65 case INTEGER_LSB_FIRST:
66 for (i = 0; i < cnt; i++)
67 value = (value << 8) | from[cnt - i - 1];
70 for (i = 0; i < (cnt & ~1); i++)
71 value = (value << 8) | from[i ^ 1];
73 value = (value << 8) | from[cnt - 1];
80 /* Stores VALUE as a CNT-byte integer at TO, in the given
83 integer_put (uint64_t value, enum integer_format format, void *to_, size_t cnt)
88 assert (is_integer_format (format));
91 value <<= 8 * (8 - cnt);
95 case INTEGER_MSB_FIRST:
96 for (i = 0; i < cnt; i++)
102 case INTEGER_LSB_FIRST:
103 for (i = 0; i < cnt; i++)
105 to[cnt - i - 1] = value >> 56;
110 for (i = 0; i < (cnt & ~1); i++)
112 to[i ^ 1] = value >> 56;
116 to[cnt - 1] = value >> 56;
121 /* Returns true if bytes with index IDX1 and IDX2 in VALUE differ
124 bytes_differ (uint64_t value, unsigned int idx1, unsigned int idx2)
126 uint8_t byte1 = value >> (idx1 * 8);
127 uint8_t byte2 = value >> (idx2 * 8);
128 return byte1 != byte2;
131 /* Attempts to identify the integer format in which the LENGTH
132 bytes in INTEGER represent the given EXPECTED_VALUE. Returns
133 true if successful, false otherwise. On success, stores the
134 format in *FORMAT. */
136 integer_identify (uint64_t expected_value, const void *integer, size_t length,
137 enum integer_format *format)
139 /* Odd-length integers are confusing. */
140 assert (length % 2 == 0);
142 /* LENGTH must be greater than 2 because VAX format is
143 equivalent to little-endian for 2-byte integers. */
146 /* EXPECTED_VALUE must contain different byte values, because
147 otherwise all formats are identical. */
148 assert (bytes_differ (expected_value, 0, 1)
149 || bytes_differ (expected_value, 0, 2)
150 || bytes_differ (expected_value, 0, 3)
152 && (bytes_differ (expected_value, 0, 4)
153 || bytes_differ (expected_value, 0, 5)))
155 && (bytes_differ (expected_value, 0, 6)
156 || bytes_differ (expected_value, 0, 7))));
158 if (integer_get (INTEGER_MSB_FIRST, integer, length) == expected_value)
159 *format = INTEGER_MSB_FIRST;
160 else if (integer_get (INTEGER_LSB_FIRST, integer, length) == expected_value)
161 *format = INTEGER_LSB_FIRST;
162 else if (integer_get (INTEGER_VAX, integer, length) == expected_value)
163 *format = INTEGER_VAX;