Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/* 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 <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
 ****************************************************************/

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 );
}