4 #include <string.h> /* memcpy() */
5 #include "diagnostic.h"
6 #include "formatutil.h"
10 #ifndef NORMAL_FP_FORMAT
11 #define INCLUDE_FORMAT_CHECKING
13 #ifndef NORMAL_INT_FORMAT
14 #define INCLUDE_FORMAT_CHECKING
19 static void *lock = NULL; /* local mutex */
20 static const size_t HOST_SIZE[SIMPLE_TYPE_COUNT] =
21 {sizeof(char), sizeof(double), sizeof(float), sizeof(int), sizeof(long),
22 sizeof(short), sizeof(unsigned int), sizeof(unsigned long),
23 sizeof(unsigned short)};
24 static const size_t NETWORK_SIZE[SIMPLE_TYPE_COUNT] =
25 {1, 8, 4, 4, 4, 2, 4, 4, 2};
27 /* how this host treat int, floats and big/little endianness */
28 static int unusualFPFormat = 0;
29 static int unusualIntFormat = 0;
30 static int bytesReversed = -1;
32 #ifndef NORMAL_FP_FORMAT
34 ** Copies #source# to #destination#, converting between IEEE and host floating-
35 ** point format. #whatType# must be DOUBLETYPE or FLOATTYPE. #hostToIEEE#
36 ** indicates whether the conversion is from host format to IEEE or vice versa.
37 ** The IEEE version of the data will be in big-endian byte order even if the
38 ** host machine is little-endian. For IEEE 754 floating point info, look at
39 ** http://www.research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
41 /* It should be thread safe */
43 ConvertIEEE( const void *destination,
48 #define DOUBLEBIAS 1023
49 #define QUADBIAS 16383
50 #define SINGLEBIAS 127
52 struct DoublePrecision {
54 unsigned exponent : 11;
56 unsigned char mantissa[6];
62 unsigned char mantissa[16];
65 struct QuadPrecision {
67 unsigned exponent : 15;
68 unsigned char mantissa[14];
69 }; /* For future reference. */
71 struct SinglePrecision {
73 unsigned exponent : 8;
75 unsigned char mantissa[2];
79 unsigned exponentBias;
82 size_t mantissaLength;
84 if(whatType == DOUBLE_TYPE) {
85 exponentBias = DOUBLEBIAS;
86 mantissaLength = sizeof(doublePrecision.mantissa) + 1;
87 factor = 16.0; /* 2.0 ^ bitsize(doublePrecision.leading) */
89 exponentBias = SINGLEBIAS;
90 mantissaLength = sizeof(singlePrecision.mantissa) + 1;
91 factor = 128.0; /* 2.0 ^ bitsize(singlePrecision.leading) */
95 if(whatType == DOUBLE_TYPE)
96 doubleValue = *(double *)source;
98 doubleValue = *(float *)source;
100 if(doubleValue < 0.0) {
102 doubleValue = -doubleValue;
106 expanded.exponent = 0;
107 if(doubleValue != 0.0) {
108 /* Determine the exponent value by iterative shifts
110 while(doubleValue >= 2.0) {
111 expanded.exponent += 1;
114 while(doubleValue < 1.0) {
115 expanded.exponent -= 1;
118 expanded.exponent += exponentBias;
122 /* Set the bytes of the mantissa by iterative shift and
124 for(i = 0; i < 16; i++) {
125 doubleValue *= factor;
126 expanded.mantissa[i] = (int)doubleValue;
127 doubleValue -= expanded.mantissa[i];
130 /* Pack the expanded version into the destination. */
131 if(whatType == DOUBLE_TYPE) {
132 memcpy(doublePrecision.mantissa, &expanded.mantissa[1], sizeof(doublePrecision.mantissa));
133 doublePrecision.leading = expanded.mantissa[0];
134 doublePrecision.exponent = expanded.exponent;
135 doublePrecision.sign = expanded.sign;
136 *(struct DoublePrecision *)destination = doublePrecision;
138 memcpy(singlePrecision.mantissa, &expanded.mantissa[1], sizeof(singlePrecision.mantissa));
139 singlePrecision.leading = expanded.mantissa[0];
140 singlePrecision.exponent = expanded.exponent;
141 singlePrecision.sign = expanded.sign;
142 *(struct SinglePrecision *)destination = singlePrecision;
145 /* Unpack the source into the expanded version. */
146 if(whatType == DOUBLE_TYPE) {
147 doublePrecision = *(struct DoublePrecision *)source;
148 expanded.sign = doublePrecision.sign;
149 expanded.exponent = doublePrecision.exponent;
150 expanded.mantissa[0] = doublePrecision.leading;
151 memcpy(&expanded.mantissa[1], doublePrecision.mantissa, sizeof(doublePrecision.mantissa));
153 singlePrecision = *(struct SinglePrecision *)source;
154 expanded.sign = singlePrecision.sign;
155 expanded.exponent = singlePrecision.exponent;
156 expanded.mantissa[0] = singlePrecision.leading;
157 memcpy(&expanded.mantissa[1], singlePrecision.mantissa, sizeof(singlePrecision.mantissa));
159 /* Set mantissa by via shifts and adds; allow for
160 * denormalized values. */
161 doubleValue = (expanded.exponent == 0) ? 0.0 : 1.0;
163 for(i = 0; i < mantissaLength; i++) {
164 doubleValue += (double)expanded.mantissa[i] / factor;
167 /* Set the exponent by iterative mults/divs by 2. */
168 if(expanded.exponent == 0)
169 ; /* Nothing to do. */
170 else if(expanded.exponent == (exponentBias * 2 + 1))
172 * An exponent of all ones represents one of
173 * three things: Infinity: mantissa of all zeros
174 * Indeterminate: sign of 1, mantissa leading one
175 * followed by all zeros NaN: all other values
176 * None of these can be reliably produced by C
177 * operations. We might be able to get Infinity
178 * by dividing by zero, but, on a non-IEEE
179 * machine, we're more likely to cause some sort
180 * of floating-point exception.
184 expanded.exponent -= exponentBias;
186 if(expanded.exponent < 0) {
187 for(i = expanded.exponent; i < 0; i++)
190 for(i = 0; i < expanded.exponent; i++)
197 if(whatType == DOUBLE_TYPE)
198 *(double *)destination = doubleValue;
200 *(float *)destination = doubleValue;
207 * Copies the integer value of size #sourceSize# stored in #source# to the
208 * #destinationSize#-long area #destination#. #signedType# indicates whether
209 * or not the source integer is signed; #lowOrderFirst# whether or not the
210 * bytes run least-significant to most-significant.
212 * It should be thread safe (operates on local variables and calls mem*)
215 ResizeInt( void *destination,
216 size_t destinationSize,
222 unsigned char *destinationSign;
224 int sizeChange = destinationSize - sourceSize;
225 unsigned char *sourceSign;
227 if(sizeChange == 0) {
228 memcpy(destination, source, destinationSize);
229 } else if(sizeChange < 0) {
230 /* Truncate high-order bytes. */
231 memcpy(destination, lowOrderFirst?source:((char*)source-sizeChange), destinationSize);
233 /* Make sure the high order bit of source and
234 * destination are the same */
235 destinationSign = lowOrderFirst ? ((unsigned char*)destination + destinationSize - 1) : (unsigned char*)destination;
236 sourceSign = lowOrderFirst ? ((unsigned char*)source + sourceSize - 1) : (unsigned char*)source;
237 if((*sourceSign > 127) != (*destinationSign > 127)) {
238 if(*sourceSign > 127)
239 *destinationSign += 128;
241 *destinationSign -= 128;
245 /* Pad with zeros or extend sign, as appropriate. */
249 sourceSign = lowOrderFirst ? ((unsigned char*)source + sourceSize - 1) : (unsigned char*)source;
250 padding = (*sourceSign > 127) ? 0xff : 0;
252 memset(destination, padding, destinationSize);
253 memcpy(lowOrderFirst ? destination : ((char *)destination + sizeChange), source, sourceSize);
259 * Copies #length# bytes from #from# to #to# in reverse order. Will work
260 * properly if #from# and #to# are the same address.
262 * It should be thread safe.
265 ReverseBytes( void *to,
270 const char *fromBegin;
275 for(fromBegin = (const char *)from, fromEnd = fromBegin + length - 1, toBegin = (char *)to, toEnd = toBegin + length - 1; fromBegin <= fromEnd; fromBegin++, fromEnd--, toBegin++, toEnd--) {
276 charBegin = *fromBegin;
284 ConvertData( void *destination,
286 const DataDescriptor *description,
288 FormatTypes sourceFormat) {
290 size_t destStructSize;
293 size_t networkBytesConverted;
295 const char *nextSource;
296 size_t sourceStructSize;
298 networkBytesConverted = 0;
300 for(i = 0; i < length; i++, description++) {
301 if(sourceFormat == HOST_FORMAT) {
302 nextDest = (char *)destination + networkBytesConverted;
303 nextSource = (char *)source + description->offset;
305 nextDest = (char *)destination + description->offset;
306 nextSource = (char *)source + networkBytesConverted;
308 if(description->type == STRUCT_TYPE) {
309 if(sourceFormat == HOST_FORMAT) {
310 destStructSize = DataSize(description->members, description->length, NETWORK_FORMAT);
311 sourceStructSize = DataSize(description->members, description->length, HOST_FORMAT) + description->tailPadding;
313 destStructSize = DataSize(description->members, description->length, HOST_FORMAT) + description->tailPadding;
314 sourceStructSize = DataSize(description->members, description->length, NETWORK_FORMAT);
316 for(j = 0; j < description->repetitions; j++) {
317 ConvertData(nextDest, nextSource, description->members, description->length, sourceFormat);
318 nextDest += destStructSize;
319 nextSource += sourceStructSize;
322 HomogenousConvertData(nextDest, nextSource, description->type, description->repetitions, sourceFormat);
324 networkBytesConverted += DataSize(description, 1, NETWORK_FORMAT);
329 /* I believe is thread safe (HomogenousDataSize is thread safe) */
331 DataSize( const DataDescriptor *description,
333 FormatTypes format) {
336 const DataDescriptor *lastMember;
339 if(format == HOST_FORMAT) {
340 lastMember = description;
341 for(i = 0; i < length; i++) {
342 if(description[i].offset > lastMember->offset) {
343 lastMember = &description[i];
346 return lastMember->offset + ((lastMember->type == STRUCT_TYPE) ? ((DataSize(lastMember->members, lastMember->length, HOST_FORMAT) + lastMember->tailPadding) * lastMember->repetitions) : HomogenousDataSize(lastMember->type, lastMember->repetitions, HOST_FORMAT));
349 for(i = 0; i < length; i++, description++) {
350 totalSize += (description->type == STRUCT_TYPE) ? (DataSize(description->members, description->length, NETWORK_FORMAT) * description->repetitions) : HomogenousDataSize(description->type, description->repetitions, NETWORK_FORMAT);
358 * Internal call to be done only once. We find the fomrat of this host:
359 * once done we re-use the results
361 * Some of the checking could have been done at compile time, but to be
362 * sure and to cover exoteric machine (doesn't ppc can behave as little
363 * and bin endian?) we do it at runtime.
365 * I believe it is thread safe (uses the lock if it modifies global
371 /* we do the checking only once: next time bytesReversed will be
373 if (bytesReversed == -1) {
374 /* I think we could avoid this lock, but just to be safe */
377 /* check endiannes */
379 typedef int IntTestType;
382 unsigned char bytes[sizeof(IntTestType)];
385 orderTester.testInt = 1;
386 bytesReversed = (orderTester.bytes[0] == 1);
389 #ifdef INCLUDE_FORMAT_CHECKING
390 # ifndef NORMAL_FP_FORMAT
392 typedef double FPTestType;
395 unsigned char bytes[sizeof(FPTestType)];
398 memset(&fpTester, 0, sizeof(fpTester));
399 /* Set sign, low-order bit of exponent and high-order bit
401 fpTester.bytes[bytesReversed ? sizeof(FPTestType) - 1 : 0]=192;
402 fpTester.bytes[bytesReversed ? sizeof(FPTestType) - 2 : 1] =
403 (sizeof(FPTestType) == 4) ? 128 :
404 (sizeof(FPTestType) == 8) ? 16 :
405 (sizeof(FPTestType) == 16) ? 1 : 0;
406 unusualFPFormat = fpTester.testFP != -4.0;
410 # ifndef NORMAL_INT_FORMAT
411 /* Converting non-twos-compliment is a pain, but
412 * detecting it is easy, so we go ahead and include a
413 * check and leave it to the caller to handle. */
415 typedef int IntTestType;
418 unsigned char bytes[sizeof(IntTestType)];
421 intTester.testInt = -2;
422 unusualIntFormat = ((unsigned int)intTester.bytes[0] +
423 (unsigned int)intTester.bytes[sizeof(IntTestType) - 1]) != 509;
428 ReleaseNWSLock(&lock);
433 /* I believe is thread safe (FirstCall is thread safe and we just read
434 * the global variables) */
436 DifferentFormat(DataTypes whatType) {
439 return ((whatType == DOUBLE_TYPE) || (whatType == FLOAT_TYPE)) ?
440 unusualFPFormat : unusualIntFormat;
444 /* I believe is thread safe (FirstCall is thread safe and we just read
445 * the global variable) */
447 DifferentOrder(void) {
450 return bytesReversed;
454 /* It should be thread sage (only reads global variables) */
456 DifferentSize(DataTypes whatType) {
457 return HOST_SIZE[whatType] != NETWORK_SIZE[whatType];
461 /* It should be thread safe (ConvertIEEE, ReverseData
462 * and mem* are thread safe) */
464 HomogenousConvertData( void *destination,
468 FormatTypes sourceFormat) {
470 int bytesReverse = DifferentOrder();
471 FormatTypes destFormat;
478 destFormat = (sourceFormat == HOST_FORMAT) ? NETWORK_FORMAT : HOST_FORMAT;
479 fromSize = (sourceFormat == HOST_FORMAT) ?
480 HOST_SIZE[whatType] : NETWORK_SIZE[whatType];
481 toSize = (destFormat == HOST_FORMAT) ?
482 HOST_SIZE[whatType] : NETWORK_SIZE[whatType];
484 #ifndef NORMAL_FP_FORMAT
485 if(((whatType == DOUBLE_TYPE) || (whatType == FLOAT_TYPE)) &&
486 (DifferentFormat(whatType) || (fromSize != toSize))) {
487 for(i = 0, from = source, to = destination; i < repetitions; i++, from = (char *)from + fromSize, to = (char *)to + toSize) {
488 ConvertIEEE(to, from, whatType, (sourceFormat == HOST_FORMAT));
490 /* Note: ConvertIEEE also handles byte ordering. */
495 if(fromSize != toSize) {
496 for(i = 0, from = source, to = destination; i < repetitions; i++, from = (char *)from + fromSize, to = (char *)to + toSize) {
497 ResizeInt(to, toSize, from, fromSize, whatType < UNSIGNED_INT_TYPE, (sourceFormat == HOST_FORMAT) && bytesReverse);
499 if(bytesReverse && (toSize > 1))
500 ReverseData(destination, destination, whatType, repetitions, destFormat);
501 } else if(bytesReverse && (toSize > 1))
502 ReverseData(destination, source, whatType, repetitions, destFormat);
503 else if(destination != source)
504 memcpy(destination, source, fromSize * repetitions);
508 /* I believe is thread safe (*_SIZE are static and global but are
509 * constant and initialize when created) */
511 HomogenousDataSize( DataTypes whatType,
513 FormatTypes format) {
514 return ((format == HOST_FORMAT) ?
515 HOST_SIZE[whatType] : NETWORK_SIZE[whatType]) * repetitions;
519 /* It should be thread safe (ReverseByte is thread safe */
521 ReverseData( void *destination,
525 FormatTypes format) {
529 size = (format == HOST_FORMAT) ? HOST_SIZE[whatType] : NETWORK_SIZE[whatType];
530 for(i = 0; i < repetitions; i++, destination = (char *)destination + size, source = (char *)source + size) {
531 ReverseBytes(destination, source, size);