diff options
Diffstat (limited to 'lib/liblame/frontend/portableio.c')
-rw-r--r-- | lib/liblame/frontend/portableio.c | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/lib/liblame/frontend/portableio.c b/lib/liblame/frontend/portableio.c new file mode 100644 index 0000000000..61c1d30d59 --- /dev/null +++ b/lib/liblame/frontend/portableio.c @@ -0,0 +1,490 @@ +/* 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); +} |