| /* Copyright (C) 1988-1991 Apple Computer, Inc. |
| * All Rights Reserved. |
| * |
| * Warranty Information |
| * Even though Apple has reviewed this software, Apple makes no warranty |
| * or representation, either express or implied, with respect to this |
| * software, its quality, accuracy, merchantability, or fitness for a |
| * particular purpose. As a result, this software is provided "as is," |
| * and you, its user, are assuming the entire risk as to its quality |
| * and accuracy. |
| * |
| * This code may be used and freely distributed as long as it includes |
| * this copyright notice and the warranty information. |
| * |
| * |
| * Motorola processors (Macintosh, Sun, Sparc, MIPS, etc) |
| * pack bytes from high to low (they are big-endian). |
| * Use the HighLow routines to match the native format |
| * of these machines. |
| * |
| * Intel-like machines (PCs, Sequent) |
| * pack bytes from low to high (the are little-endian). |
| * Use the LowHigh routines to match the native format |
| * of these machines. |
| * |
| * These routines have been tested on the following machines: |
| * Apple Macintosh, MPW 3.1 C compiler |
| * Apple Macintosh, THINK C compiler |
| * Silicon Graphics IRIS, MIPS compiler |
| * Cray X/MP and Y/MP |
| * Digital Equipment VAX |
| * |
| * |
| * Implemented by Malcolm Slaney and Ken Turkowski. |
| * |
| * Malcolm Slaney contributions during 1988-1990 include big- and little- |
| * endian file I/O, conversion to and from Motorola's extended 80-bit |
| * floating-point format, and conversions to and from IEEE single- |
| * precision floating-point format. |
| * |
| * In 1991, Ken Turkowski implemented the conversions to and from |
| * IEEE double-precision format, added more precision to the extended |
| * conversions, and accommodated conversions involving +/- infinity, |
| * NaN's, and denormalized numbers. |
| * |
| * $Id: portableio.c,v 1.13 2007/10/14 19:54:32 robert Exp $ |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include <config.h> |
| #endif |
| |
| #include <stdio.h> |
| #if defined(__riscos__) && defined(FPA10) |
| #include "ymath.h" |
| #else |
| #include <math.h> |
| #endif |
| #include "portableio.h" |
| |
| #ifdef WITH_DMALLOC |
| #include <dmalloc.h> |
| #endif |
| |
| /**************************************************************** |
| * Big/little-endian independent I/O routines. |
| ****************************************************************/ |
| |
| /* |
| * It is a hoax to call this code portable-IO: |
| * |
| * - It doesn't work on machines with CHAR_BIT != 8 |
| * - it also don't test this error condition |
| * - otherwise it tries to handle CHAR_BIT != 8 by things like |
| * masking 'putc(i&0xff,fp)' |
| * - It doesn't handle EOF in any way |
| * - it only works with ints with 32 or more bits |
| * - It is a collection of initial buggy code with patching the known errors |
| * instead of CORRECTING them! |
| * For that see comments on the old Read16BitsHighLow() |
| */ |
| |
| #ifdef KLEMM_36 |
| |
| signed int |
| ReadByte(FILE * fp) |
| { |
| int result = getc(fp); |
| return result == EOF ? 0 : (signed char) (result & 0xFF); |
| } |
| |
| unsigned int |
| ReadByteUnsigned(FILE * fp) |
| { |
| int result = getc(fp); |
| return result == EOF ? 0 : (unsigned char) (result & 0xFF); |
| } |
| |
| #else |
| |
| int |
| ReadByte(FILE * fp) |
| { |
| int result; |
| |
| result = getc(fp) & 0xff; |
| if (result & 0x80) |
| result = result - 0x100; |
| return result; |
| } |
| |
| #endif |
| |
| #ifdef KLEMM_36 |
| |
| int |
| Read16BitsLowHigh(FILE * fp) |
| { |
| int low = ReadByteUnsigned(fp); |
| int high = ReadByte(fp); |
| |
| return (high << 8) | low; |
| } |
| |
| #else |
| int |
| Read16BitsLowHigh(FILE * fp) |
| { |
| int first, second, result; |
| |
| first = 0xff & getc(fp); |
| second = 0xff & getc(fp); |
| |
| result = (second << 8) + first; |
| #ifndef THINK_C42 |
| if (result & 0x8000) |
| result = result - 0x10000; |
| #endif /* THINK_C */ |
| return (result); |
| } |
| #endif |
| |
| |
| #ifdef KLEMM_36 |
| |
| int |
| Read16BitsHighLow(FILE * fp) |
| { |
| int high = ReadByte(fp); |
| int low = ReadByteUnsigned(fp); |
| |
| return (high << 8) | low; |
| } |
| |
| #else |
| int |
| Read16BitsHighLow(FILE * fp) |
| { |
| int first, second, result; |
| |
| /* Reads the High bits, the value is -128...127 |
| * (which gave after upscaling the -32768...+32512 |
| * Why this value is not converted to signed char? |
| */ |
| first = 0xff & getc(fp); |
| /* Reads the Lows bits, the value is 0...255 |
| * This is correct. This value gives an additional offset |
| * for the High bits |
| */ |
| second = 0xff & getc(fp); |
| |
| /* This is right */ |
| result = (first << 8) + second; |
| |
| /* Now we are starting to correct the nasty bug of the first instruction |
| * The value of the high bits is wrong. Always. So we must correct this |
| * value. This seems to be not necessary for THINK_C42. This is either |
| * a 16 bit compiler with 16 bit ints (where this bug is hidden and 0x10000 |
| * is not in the scope of an int) or it is not a C compiler, but only a |
| * C like compiler. In the first case the '#ifndef THINK_C42' is wrong |
| * because it's not a property of the THINK_C42 compiler, but of all compilers |
| * with sizeof(int)*CHAR_BIT < 18. |
| * Another nasty thing is that the rest of the code doesn't work for 16 bit ints, |
| * so this patch don't solve the 16 bit problem. |
| */ |
| #ifndef THINK_C42 |
| if (result & 0x8000) |
| result = result - 0x10000; |
| #endif /* THINK_C */ |
| return (result); |
| } |
| #endif |
| |
| void |
| Write8Bits(FILE * fp, int i) |
| { |
| putc(i & 0xff, fp); |
| } |
| |
| |
| void |
| Write16BitsLowHigh(FILE * fp, int i) |
| { |
| putc(i & 0xff, fp); |
| putc((i >> 8) & 0xff, fp); |
| } |
| |
| |
| void |
| Write16BitsHighLow(FILE * fp, int i) |
| { |
| putc((i >> 8) & 0xff, fp); |
| putc(i & 0xff, fp); |
| } |
| |
| #ifdef KLEMM_36 |
| |
| int |
| Read24BitsHighLow(FILE * fp) |
| { |
| int high = ReadByte(fp); |
| int med = ReadByteUnsigned(fp); |
| int low = ReadByteUnsigned(fp); |
| |
| return (high << 16) | (med << 8) | low; |
| } |
| |
| #else |
| int |
| Read24BitsHighLow(FILE * fp) |
| { |
| int first, second, third; |
| int result; |
| |
| first = 0xff & getc(fp); |
| second = 0xff & getc(fp); |
| third = 0xff & getc(fp); |
| |
| result = (first << 16) + (second << 8) + third; |
| if (result & 0x800000) |
| result = result - 0x1000000; |
| return (result); |
| } |
| #endif |
| |
| #define Read32BitsLowHigh(f) Read32Bits(f) |
| |
| #ifdef KLEMM_36 |
| |
| int |
| Read32Bits(FILE * fp) |
| { |
| int low = ReadByteUnsigned(fp); |
| int medl = ReadByteUnsigned(fp); |
| int medh = ReadByteUnsigned(fp); |
| int high = ReadByte(fp); |
| |
| return (high << 24) | (medh << 16) | (medl << 8) | low; |
| } |
| |
| #else |
| |
| int |
| Read32Bits(FILE * fp) |
| { |
| int first, second, result; |
| |
| first = 0xffff & Read16BitsLowHigh(fp); |
| second = 0xffff & Read16BitsLowHigh(fp); |
| |
| result = (second << 16) + first; |
| #ifdef CRAY |
| if (result & 0x80000000) |
| result = result - 0x100000000; |
| #endif /* CRAY */ |
| return (result); |
| } |
| #endif |
| |
| |
| #ifdef KLEMM_36 |
| |
| int |
| Read32BitsHighLow(FILE * fp) |
| { |
| int high = ReadByte(fp); |
| int medh = ReadByteUnsigned(fp); |
| int medl = ReadByteUnsigned(fp); |
| int low = ReadByteUnsigned(fp); |
| |
| return (high << 24) | (medh << 16) | (medl << 8) | low; |
| } |
| |
| #else |
| |
| int |
| Read32BitsHighLow(FILE * fp) |
| { |
| int first, second, result; |
| |
| first = 0xffff & Read16BitsHighLow(fp); |
| second = 0xffff & Read16BitsHighLow(fp); |
| |
| result = (first << 16) + second; |
| #ifdef CRAY |
| if (result & 0x80000000) |
| result = result - 0x100000000; |
| #endif |
| return (result); |
| } |
| |
| #endif |
| |
| void |
| Write32Bits(FILE * fp, int i) |
| { |
| Write16BitsLowHigh(fp, (int) (i & 0xffffL)); |
| Write16BitsLowHigh(fp, (int) ((i >> 16) & 0xffffL)); |
| } |
| |
| |
| void |
| Write32BitsLowHigh(FILE * fp, int i) |
| { |
| Write16BitsLowHigh(fp, (int) (i & 0xffffL)); |
| Write16BitsLowHigh(fp, (int) ((i >> 16) & 0xffffL)); |
| } |
| |
| |
| void |
| Write32BitsHighLow(FILE * fp, int i) |
| { |
| Write16BitsHighLow(fp, (int) ((i >> 16) & 0xffffL)); |
| Write16BitsHighLow(fp, (int) (i & 0xffffL)); |
| } |
| |
| #ifdef KLEMM_36 |
| void |
| ReadBytes(FILE * fp, char *p, int n) |
| { |
| memset(p, 0, n); |
| fread(p, 1, n, fp); |
| } |
| #else |
| void |
| ReadBytes(FILE * fp, char *p, int n) |
| { |
| /* What about fread? */ |
| |
| while (!feof(fp) & (n-- > 0)) |
| *p++ = getc(fp); |
| } |
| #endif |
| |
| void |
| ReadBytesSwapped(FILE * fp, char *p, int n) |
| { |
| register char *q = p; |
| |
| /* What about fread? */ |
| |
| while (!feof(fp) & (n-- > 0)) |
| *q++ = getc(fp); |
| |
| /* If not all bytes could be read, the resorting is different |
| * from the normal resorting. Is this intention or another bug? |
| */ |
| for (q--; p < q; p++, q--) { |
| n = *p; |
| *p = *q; |
| *q = n; |
| } |
| } |
| |
| #ifdef KLEMM_36 |
| void |
| WriteBytes(FILE * fp, char *p, int n) |
| { |
| /* return n == */ |
| fwrite(p, 1, n, fp); |
| } |
| #else |
| void |
| WriteBytes(FILE * fp, char *p, int n) |
| { |
| /* No error condition checking */ |
| while (n-- > 0) |
| putc(*p++, fp); |
| } |
| #endif |
| #ifdef KLEMM_36 |
| void |
| WriteBytesSwapped(FILE * fp, char *p, int n) |
| { |
| p += n; |
| while (n-- > 0) |
| putc(*--p, fp); |
| } |
| #else |
| void |
| WriteBytesSwapped(FILE * fp, char *p, int n) |
| { |
| p += n - 1; |
| while (n-- > 0) |
| putc(*p--, fp); |
| } |
| #endif |
| |
| |
| |
| /**************************************************************** |
| * The following two routines make up for deficiencies in many |
| * compilers to convert properly between unsigned integers and |
| * floating-point. Some compilers which have this bug are the |
| * THINK_C compiler for the Macintosh and the C compiler for the |
| * Silicon Graphics MIPS-based Iris. |
| ****************************************************************/ |
| |
| #ifdef applec /* The Apple C compiler works */ |
| # define FloatToUnsigned(f) ((unsigned long)(f)) |
| # define UnsignedToFloat(u) ((double)(u)) |
| #else /* applec */ |
| # define FloatToUnsigned(f) ((unsigned long)(((long)((f) - 2147483648.0)) + 2147483647L + 1)) |
| # define UnsignedToFloat(u) (((double)((long)((u) - 2147483647L - 1))) + 2147483648.0) |
| #endif /* applec */ |
| /**************************************************************** |
| * Extended precision IEEE floating-point conversion routines |
| ****************************************************************/ |
| |
| static double |
| ConvertFromIeeeExtended(char *bytes) |
| { |
| double f; |
| long expon; |
| unsigned long hiMant, loMant; |
| |
| #ifdef TEST |
| printf("ConvertFromIEEEExtended(%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx\r", |
| (long) bytes[0], (long) bytes[1], (long) bytes[2], (long) bytes[3], |
| (long) bytes[4], (long) bytes[5], (long) bytes[6], |
| (long) bytes[7], (long) bytes[8], (long) bytes[9]); |
| #endif |
| |
| expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); |
| hiMant = ((unsigned long) (bytes[2] & 0xFF) << 24) |
| | ((unsigned long) (bytes[3] & 0xFF) << 16) |
| | ((unsigned long) (bytes[4] & 0xFF) << 8) |
| | ((unsigned long) (bytes[5] & 0xFF)); |
| loMant = ((unsigned long) (bytes[6] & 0xFF) << 24) |
| | ((unsigned long) (bytes[7] & 0xFF) << 16) |
| | ((unsigned long) (bytes[8] & 0xFF) << 8) |
| | ((unsigned long) (bytes[9] & 0xFF)); |
| |
| /* This case should also be called if the number is below the smallest |
| * positive double variable */ |
| if (expon == 0 && hiMant == 0 && loMant == 0) { |
| f = 0; |
| } |
| else { |
| /* This case should also be called if the number is too large to fit into |
| * a double variable */ |
| |
| if (expon == 0x7FFF) { /* Infinity or NaN */ |
| f = HUGE_VAL; |
| } |
| else { |
| expon -= 16383; |
| f = ldexp(UnsignedToFloat(hiMant), (int) (expon -= 31)); |
| f += ldexp(UnsignedToFloat(loMant), (int) (expon -= 32)); |
| } |
| } |
| |
| if (bytes[0] & 0x80) |
| return -f; |
| else |
| return f; |
| } |
| |
| |
| |
| |
| |
| double |
| ReadIeeeExtendedHighLow(FILE * fp) |
| { |
| char bytes[10]; |
| |
| ReadBytes(fp, bytes, 10); |
| return ConvertFromIeeeExtended(bytes); |
| } |