portableio.c

Go to the documentation of this file.
00001 /* Copyright (C) 1988-1991 Apple Computer, Inc.
00002  * All Rights Reserved.
00003  *
00004  * Warranty Information
00005  * Even though Apple has reviewed this software, Apple makes no warranty
00006  * or representation, either express or implied, with respect to this
00007  * software, its quality, accuracy, merchantability, or fitness for a
00008  * particular purpose.  As a result, this software is provided "as is,"
00009  * and you, its user, are assuming the entire risk as to its quality
00010  * and accuracy.
00011  *
00012  * This code may be used and freely distributed as long as it includes
00013  * this copyright notice and the warranty information.
00014  *
00015  *
00016  * Motorola processors (Macintosh, Sun, Sparc, MIPS, etc)
00017  * pack bytes from high to low (they are big-endian).
00018  * Use the HighLow routines to match the native format
00019  * of these machines.
00020  *
00021  * Intel-like machines (PCs, Sequent)
00022  * pack bytes from low to high (the are little-endian).
00023  * Use the LowHigh routines to match the native format
00024  * of these machines.
00025  *
00026  * These routines have been tested on the following machines:
00027  *      Apple Macintosh, MPW 3.1 C compiler
00028  *      Apple Macintosh, THINK C compiler
00029  *      Silicon Graphics IRIS, MIPS compiler
00030  *      Cray X/MP and Y/MP
00031  *      Digital Equipment VAX
00032  *
00033  *
00034  * Implemented by Malcolm Slaney and Ken Turkowski.
00035  *
00036  * Malcolm Slaney contributions during 1988-1990 include big- and little-
00037  * endian file I/O, conversion to and from Motorola's extended 80-bit
00038  * floating-point format, and conversions to and from IEEE single-
00039  * precision floating-point format.
00040  *
00041  * In 1991, Ken Turkowski implemented the conversions to and from
00042  * IEEE double-precision format, added more precision to the extended
00043  * conversions, and accommodated conversions involving +/- infinity,
00044  * NaN's, and denormalized numbers.
00045  *
00046  * $Id: portableio.c,v 1.12 2005/11/01 13:01:57 robert Exp $
00047  */
00048 
00049 #ifdef HAVE_CONFIG_H
00050 # include <config.h>
00051 #endif
00052 
00053 #include        <stdio.h>
00054 #if defined(__riscos__) && defined(FPA10)
00055 #include        "ymath.h"
00056 #else
00057 #include        <math.h>
00058 #endif
00059 #include        "portableio.h"
00060 
00061 #ifdef WITH_DMALLOC
00062 #include <dmalloc.h>
00063 #endif
00064 
00065 /****************************************************************
00066  * Big/little-endian independent I/O routines.
00067  ****************************************************************/
00068 
00069 /*
00070  * It is a hoax to call this code portable-IO:
00071  * 
00072  *   - It doesn't work on machines with CHAR_BIT != 8
00073  *   - it also don't test this error condition
00074  *   - otherwise it tries to handle CHAR_BIT != 8 by things like 
00075  *     masking 'putc(i&0xff,fp)'
00076  *   - It doesn't handle EOF in any way
00077  *   - it only works with ints with 32 or more bits
00078  *   - It is a collection of initial buggy code with patching the known errors
00079  *     instead of CORRECTING them! 
00080  *     For that see comments on the old Read16BitsHighLow()
00081  */
00082 
00083 #ifdef KLEMM_36
00084 
00085 signed int
00086 ReadByte(FILE * fp)
00087 {
00088     int     result = getc(fp);
00089     return result == EOF ? 0 : (signed char) (result & 0xFF);
00090 }
00091 
00092 unsigned int
00093 ReadByteUnsigned(FILE * fp)
00094 {
00095     int     result = getc(fp);
00096     return result == EOF ? 0 : (unsigned char) (result & 0xFF);
00097 }
00098 
00099 #else
00100 
00101 int
00102 ReadByte(FILE * fp)
00103 {
00104     int     result;
00105 
00106     result = getc(fp) & 0xff;
00107     if (result & 0x80)
00108         result = result - 0x100;
00109     return result;
00110 }
00111 
00112 #endif
00113 
00114 #ifdef KLEMM_36
00115 
00116 int
00117 Read16BitsLowHigh(FILE * fp)
00118 {
00119     int     low = ReadByteUnsigned(fp);
00120     int     high = ReadByte(fp);
00121 
00122     return (high << 8) | low;
00123 }
00124 
00125 #else
00126 int
00127 Read16BitsLowHigh(FILE * fp)
00128 {
00129     int     first, second, result;
00130 
00131     first = 0xff & getc(fp);
00132     second = 0xff & getc(fp);
00133 
00134     result = (second << 8) + first;
00135 #ifndef THINK_C42
00136     if (result & 0x8000)
00137         result = result - 0x10000;
00138 #endif /* THINK_C */
00139     return (result);
00140 }
00141 #endif
00142 
00143 
00144 #ifdef KLEMM_36
00145 
00146 int
00147 Read16BitsHighLow(FILE * fp)
00148 {
00149     int     high = ReadByte(fp);
00150     int     low = ReadByteUnsigned(fp);
00151 
00152     return (high << 8) | low;
00153 }
00154 
00155 #else
00156 int
00157 Read16BitsHighLow(FILE * fp)
00158 {
00159     int     first, second, result;
00160 
00161     /* Reads the High bits, the value is -128...127 
00162      * (which gave after upscaling the -32768...+32512
00163      * Why this value is not converted to signed char?
00164      */
00165     first = 0xff & getc(fp);
00166     /* Reads the Lows bits, the value is 0...255 
00167      * This is correct. This value gives an additional offset
00168      * for the High bits
00169      */
00170     second = 0xff & getc(fp);
00171 
00172     /* This is right */
00173     result = (first << 8) + second;
00174 
00175     /* Now we are starting to correct the nasty bug of the first instruction
00176      * The value of the high bits is wrong. Always. So we must correct this
00177      * value. This seems to be not necessary for THINK_C42. This is either
00178      * a 16 bit compiler with 16 bit ints (where this bug is hidden and 0x10000
00179      * is not in the scope of an int) or it is not a C compiler, but only a
00180      * C like compiler. In the first case the '#ifndef THINK_C42' is wrong
00181      * because it's not a property of the THINK_C42 compiler, but of all compilers
00182      * with sizeof(int)*CHAR_BIT < 18.
00183      * Another nasty thing is that the rest of the code doesn't work for 16 bit ints,
00184      * so this patch don't solve the 16 bit problem.
00185      */
00186 #ifndef THINK_C42
00187     if (result & 0x8000)
00188         result = result - 0x10000;
00189 #endif /* THINK_C */
00190     return (result);
00191 }
00192 #endif
00193 
00194 void
00195 Write8Bits(FILE * fp, int i)
00196 {
00197     putc(i & 0xff, fp);
00198 }
00199 
00200 
00201 void
00202 Write16BitsLowHigh(FILE * fp, int i)
00203 {
00204     putc(i & 0xff, fp);
00205     putc((i >> 8) & 0xff, fp);
00206 }
00207 
00208 
00209 void
00210 Write16BitsHighLow(FILE * fp, int i)
00211 {
00212     putc((i >> 8) & 0xff, fp);
00213     putc(i & 0xff, fp);
00214 }
00215 
00216 #ifdef KLEMM_36
00217 
00218 int
00219 Read24BitsHighLow(FILE * fp)
00220 {
00221     int     high = ReadByte(fp);
00222     int     med = ReadByteUnsigned(fp);
00223     int     low = ReadByteUnsigned(fp);
00224 
00225     return (high << 16) | (med << 8) | low;
00226 }
00227 
00228 #else
00229 int
00230 Read24BitsHighLow(FILE * fp)
00231 {
00232     int     first, second, third;
00233     int     result;
00234 
00235     first = 0xff & getc(fp);
00236     second = 0xff & getc(fp);
00237     third = 0xff & getc(fp);
00238 
00239     result = (first << 16) + (second << 8) + third;
00240     if (result & 0x800000)
00241         result = result - 0x1000000;
00242     return (result);
00243 }
00244 #endif
00245 
00246 #define Read32BitsLowHigh(f)    Read32Bits(f)
00247 
00248 #ifdef KLEMM_36
00249 
00250 int
00251 Read32Bits(FILE * fp)
00252 {
00253     int     low = ReadByteUnsigned(fp);
00254     int     medl = ReadByteUnsigned(fp);
00255     int     medh = ReadByteUnsigned(fp);
00256     int     high = ReadByte(fp);
00257 
00258     return (high << 24) | (medh << 16) | (medl << 8) | low;
00259 }
00260 
00261 #else
00262 
00263 int
00264 Read32Bits(FILE * fp)
00265 {
00266     int     first, second, result;
00267 
00268     first = 0xffff & Read16BitsLowHigh(fp);
00269     second = 0xffff & Read16BitsLowHigh(fp);
00270 
00271     result = (second << 16) + first;
00272 #ifdef  CRAY
00273     if (result & 0x80000000)
00274         result = result - 0x100000000;
00275 #endif /* CRAY */
00276     return (result);
00277 }
00278 #endif
00279 
00280 
00281 #ifdef KLEMM_36
00282 
00283 int
00284 Read32BitsHighLow(FILE * fp)
00285 {
00286     int     high = ReadByte(fp);
00287     int     medh = ReadByteUnsigned(fp);
00288     int     medl = ReadByteUnsigned(fp);
00289     int     low = ReadByteUnsigned(fp);
00290 
00291     return (high << 24) | (medh << 16) | (medl << 8) | low;
00292 }
00293 
00294 #else
00295 
00296 int
00297 Read32BitsHighLow(FILE * fp)
00298 {
00299     int     first, second, result;
00300 
00301     first = 0xffff & Read16BitsHighLow(fp);
00302     second = 0xffff & Read16BitsHighLow(fp);
00303 
00304     result = (first << 16) + second;
00305 #ifdef  CRAY
00306     if (result & 0x80000000)
00307         result = result - 0x100000000;
00308 #endif
00309     return (result);
00310 }
00311 
00312 #endif
00313 
00314 void
00315 Write32Bits(FILE * fp, int i)
00316 {
00317     Write16BitsLowHigh(fp, (int) (i & 0xffffL));
00318     Write16BitsLowHigh(fp, (int) ((i >> 16) & 0xffffL));
00319 }
00320 
00321 
00322 void
00323 Write32BitsLowHigh(FILE * fp, int i)
00324 {
00325     Write16BitsLowHigh(fp, (int) (i & 0xffffL));
00326     Write16BitsLowHigh(fp, (int) ((i >> 16) & 0xffffL));
00327 }
00328 
00329 
00330 void
00331 Write32BitsHighLow(FILE * fp, int i)
00332 {
00333     Write16BitsHighLow(fp, (int) ((i >> 16) & 0xffffL));
00334     Write16BitsHighLow(fp, (int) (i & 0xffffL));
00335 }
00336 
00337 #ifdef KLEMM_36
00338 void
00339 ReadBytes(FILE * fp, char *p, int n)
00340 {
00341     memset(p, 0, n);
00342     fread(p, 1, n, fp);
00343 }
00344 #else
00345 void
00346 ReadBytes(FILE * fp, char *p, int n)
00347 {
00348     /* What about fread? */
00349 
00350     while (!feof(fp) & (n-- > 0))
00351         *p++ = getc(fp);
00352 }
00353 #endif
00354 
00355 void
00356 ReadBytesSwapped(FILE * fp, char *p, int n)
00357 {
00358     register char *q = p;
00359 
00360     /* What about fread? */
00361 
00362     while (!feof(fp) & (n-- > 0))
00363         *q++ = getc(fp);
00364 
00365     /* If not all bytes could be read, the resorting is different
00366      * from the normal resorting. Is this intention or another bug?
00367      */
00368     for (q--; p < q; p++, q--) {
00369         n = *p;
00370         *p = *q;
00371         *q = n;
00372     }
00373 }
00374 
00375 #ifdef KLEMM_36
00376 void
00377 WriteBytes(FILE * fp, char *p, int n)
00378 {
00379     /* return n == */
00380     fwrite(p, 1, n, fp);
00381 }
00382 #else
00383 void
00384 WriteBytes(FILE * fp, char *p, int n)
00385 {
00386     /* No error condition checking */
00387     while (n-- > 0)
00388         putc(*p++, fp);
00389 }
00390 #endif
00391 #ifdef KLEMM_36
00392 void
00393 WriteBytesSwapped(FILE * fp, char *p, int n)
00394 {
00395     p += n;
00396     while (n-- > 0)
00397         putc(*--p, fp);
00398 }
00399 #else
00400 void
00401 WriteBytesSwapped(FILE * fp, char *p, int n)
00402 {
00403     p += n - 1;
00404     while (n-- > 0)
00405         putc(*p--, fp);
00406 }
00407 #endif
00408 
00409 
00410 
00411 /****************************************************************
00412  * The following two routines make up for deficiencies in many
00413  * compilers to convert properly between unsigned integers and
00414  * floating-point.  Some compilers which have this bug are the
00415  * THINK_C compiler for the Macintosh and the C compiler for the
00416  * Silicon Graphics MIPS-based Iris.
00417  ****************************************************************/
00418 
00419 #ifdef applec           /* The Apple C compiler works */
00420 # define FloatToUnsigned(f)     ((unsigned long)(f))
00421 # define UnsignedToFloat(u)     ((double)(u))
00422 #else /* applec */
00423 # define FloatToUnsigned(f)     ((unsigned long)(((long)((f) - 2147483648.0)) + 2147483647L + 1))
00424 # define UnsignedToFloat(u)     (((double)((long)((u) - 2147483647L - 1))) + 2147483648.0)
00425 #endif /* applec */
00426 /****************************************************************
00427  * Extended precision IEEE floating-point conversion routines
00428  ****************************************************************/
00429 
00430 double
00431 ConvertFromIeeeExtended(char *bytes)
00432 {
00433     double  f;
00434     long    expon;
00435     unsigned long hiMant, loMant;
00436 
00437 #ifdef  TEST
00438     printf("ConvertFromIEEEExtended(%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx\r",
00439            (long) bytes[0], (long) bytes[1], (long) bytes[2], (long) bytes[3],
00440            (long) bytes[4], (long) bytes[5], (long) bytes[6],
00441            (long) bytes[7], (long) bytes[8], (long) bytes[9]);
00442 #endif
00443 
00444     expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
00445     hiMant = ((unsigned long) (bytes[2] & 0xFF) << 24)
00446         | ((unsigned long) (bytes[3] & 0xFF) << 16)
00447         | ((unsigned long) (bytes[4] & 0xFF) << 8)
00448         | ((unsigned long) (bytes[5] & 0xFF));
00449     loMant = ((unsigned long) (bytes[6] & 0xFF) << 24)
00450         | ((unsigned long) (bytes[7] & 0xFF) << 16)
00451         | ((unsigned long) (bytes[8] & 0xFF) << 8)
00452         | ((unsigned long) (bytes[9] & 0xFF));
00453 
00454     /* This case should also be called if the number is below the smallest
00455      * positive double variable */
00456     if (expon == 0 && hiMant == 0 && loMant == 0) {
00457         f = 0;
00458     }
00459     else {
00460         /* This case should also be called if the number is too large to fit into 
00461          * a double variable */
00462 
00463         if (expon == 0x7FFF) { /* Infinity or NaN */
00464             f = HUGE_VAL;
00465         }
00466         else {
00467             expon -= 16383;
00468             f = ldexp(UnsignedToFloat(hiMant), (int) (expon -= 31));
00469             f += ldexp(UnsignedToFloat(loMant), (int) (expon -= 32));
00470         }
00471     }
00472 
00473     if (bytes[0] & 0x80)
00474         return -f;
00475     else
00476         return f;
00477 }
00478 
00479 
00480 
00481 
00482 
00483 double
00484 ReadIeeeExtendedHighLow(FILE * fp)
00485 {
00486     char    bytes[10];
00487 
00488     ReadBytes(fp, bytes, 10);
00489     return ConvertFromIeeeExtended(bytes);
00490 }

Generated on Sun Dec 2 11:34:18 2007 for LAME by  doxygen 1.5.2