/* 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.11 2001/01/07 23:47:38 markt Exp $ */ #ifdef HAVE_CONFIG_H # include #endif #include #if defined(__riscos__) && defined(FPA10) #include "ymath.h" #else #include #endif #include "portableio.h" #ifdef WITH_DMALLOC #include #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 ****************************************************************/ 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 ); }