xref: /plan9/sys/src/games/mp3enc/portableio.c (revision 8f5875f3e9b20916b4c52ad4336922bc8653eb7b)
1 /* Copyright (C) 1988-1991 Apple Computer, Inc.
2  * All Rights Reserved.
3  *
4  * Warranty Information
5  * Even though Apple has reviewed this software, Apple makes no warranty
6  * or representation, either express or implied, with respect to this
7  * software, its quality, accuracy, merchantability, or fitness for a
8  * particular purpose.  As a result, this software is provided "as is,"
9  * and you, its user, are assuming the entire risk as to its quality
10  * and accuracy.
11  *
12  * This code may be used and freely distributed as long as it includes
13  * this copyright notice and the warranty information.
14  *
15  *
16  * Motorola processors (Macintosh, Sun, Sparc, MIPS, etc)
17  * pack bytes from high to low (they are big-endian).
18  * Use the HighLow routines to match the native format
19  * of these machines.
20  *
21  * Intel-like machines (PCs, Sequent)
22  * pack bytes from low to high (the are little-endian).
23  * Use the LowHigh routines to match the native format
24  * of these machines.
25  *
26  * These routines have been tested on the following machines:
27  *	Apple Macintosh, MPW 3.1 C compiler
28  *	Apple Macintosh, THINK C compiler
29  *	Silicon Graphics IRIS, MIPS compiler
30  *	Cray X/MP and Y/MP
31  *	Digital Equipment VAX
32  *
33  *
34  * Implemented by Malcolm Slaney and Ken Turkowski.
35  *
36  * Malcolm Slaney contributions during 1988-1990 include big- and little-
37  * endian file I/O, conversion to and from Motorola's extended 80-bit
38  * floating-point format, and conversions to and from IEEE single-
39  * precision floating-point format.
40  *
41  * In 1991, Ken Turkowski implemented the conversions to and from
42  * IEEE double-precision format, added more precision to the extended
43  * conversions, and accommodated conversions involving +/- infinity,
44  * NaN's, and denormalized numbers.
45  *
46  * $Id: portableio.c,v 1.11 2001/01/07 23:47:38 markt Exp $
47  */
48 
49 #ifdef HAVE_CONFIG_H
50 # include <config.h>
51 #endif
52 
53 #include	<stdio.h>
54 #if defined(__riscos__) && defined(FPA10)
55 #include	"ymath.h"
56 #else
57 #include	<math.h>
58 #endif
59 #include	"portableio.h"
60 
61 #ifdef WITH_DMALLOC
62 #include <dmalloc.h>
63 #endif
64 
65 /****************************************************************
66  * Big/little-endian independent I/O routines.
67  ****************************************************************/
68 
69 /*
70  * It is a hoax to call this code portable-IO:
71  *
72  *   - It doesn't work on machines with CHAR_BIT != 8
73  *   - it also don't test this error condition
74  *   - otherwise it tries to handle CHAR_BIT != 8 by things like
75  *     masking 'putc(i&0xff,fp)'
76  *   - It doesn't handle EOF in any way
77  *   - it only works with ints with 32 or more bits
78  *   - It is a collection of initial buggy code with patching the known errors
79  *     instead of CORRECTING them!
80  *     For that see comments on the old Read16BitsHighLow()
81  */
82 
83 #ifdef KLEMM_36
84 
ReadByte(FILE * fp)85 signed int    ReadByte ( FILE* fp )
86 {
87     int  result = getc (fp);
88     return result == EOF  ?  0  :  (signed char) (result & 0xFF);
89 }
90 
ReadByteUnsigned(FILE * fp)91 unsigned int  ReadByteUnsigned ( FILE* fp )
92 {
93     int  result = getc (fp);
94     return result == EOF  ?  0  :  (unsigned char) (result & 0xFF);
95 }
96 
97 #else
98 
99 int
ReadByte(FILE * fp)100 ReadByte(FILE *fp)
101 {
102 	int	result;
103 
104 	result = getc(fp) & 0xff;
105 	if (result & 0x80)
106 		result = result - 0x100;
107 	return result;
108 }
109 
110 #endif
111 
112 #ifdef KLEMM_36
113 
Read16BitsLowHigh(FILE * fp)114 int  Read16BitsLowHigh ( FILE* fp )
115 {
116     int  low  = ReadByteUnsigned (fp);
117     int  high = ReadByte         (fp);
118 
119     return (high << 8) | low;
120 }
121 
122 #else
123 int
Read16BitsLowHigh(FILE * fp)124 Read16BitsLowHigh(FILE *fp)
125 {
126 	int	first, second, result;
127 
128 	first = 0xff & getc(fp);
129 	second = 0xff & getc(fp);
130 
131 	result = (second << 8) + first;
132 #ifndef	THINK_C42
133 	if (result & 0x8000)
134 		result = result - 0x10000;
135 #endif	/* THINK_C */
136 	return(result);
137 }
138 #endif
139 
140 
141 #ifdef KLEMM_36
142 
Read16BitsHighLow(FILE * fp)143 int  Read16BitsHighLow ( FILE* fp )
144 {
145     int  high = ReadByte         (fp);
146     int  low  = ReadByteUnsigned (fp);
147 
148     return (high << 8) | low;
149 }
150 
151 #else
152 int
Read16BitsHighLow(FILE * fp)153 Read16BitsHighLow(FILE *fp)
154 {
155 	int	first, second, result;
156 
157         /* Reads the High bits, the value is -128...127
158 	 * (which gave after upscaling the -32768...+32512
159 	 * Why this value is not converted to signed char?
160 	 */
161         first = 0xff & getc(fp);
162         /* Reads the Lows bits, the value is 0...255
163 	 * This is correct. This value gives an additional offset
164 	 * for the High bits
165 	 */
166 	second = 0xff & getc(fp);
167 
168         /* This is right */
169 	result = (first << 8) + second;
170 
171         /* Now we are starting to correct the nasty bug of the first instruction
172 	 * The value of the high bits is wrong. Always. So we must correct this
173 	 * value. This seems to be not necessary for THINK_C42. This is either
174 	 * a 16 bit compiler with 16 bit ints (where this bug is hidden and 0x10000
175 	 * is not in the scope of an int) or it is not a C compiler, but only a
176 	 * C like compiler. In the first case the '#ifndef THINK_C42' is wrong
177 	 * because it's not a property of the THINK_C42 compiler, but of all compilers
178 	 * with sizeof(int)*CHAR_BIT < 18.
179 	 * Another nasty thing is that the rest of the code doesn't work for 16 bit ints,
180 	 * so this patch don't solve the 16 bit problem.
181          */
182 #ifndef	THINK_C42
183 	if (result & 0x8000)
184 		result = result - 0x10000;
185 #endif	/* THINK_C */
186 	return(result);
187 }
188 #endif
189 
190 void
Write8Bits(FILE * fp,int i)191 Write8Bits(FILE *fp, int i)
192 {
193 	putc(i&0xff,fp);
194 }
195 
196 
197 void
Write16BitsLowHigh(FILE * fp,int i)198 Write16BitsLowHigh(FILE *fp, int i)
199 {
200 	putc(i&0xff,fp);
201 	putc((i>>8)&0xff,fp);
202 }
203 
204 
205 void
Write16BitsHighLow(FILE * fp,int i)206 Write16BitsHighLow(FILE *fp, int i)
207 {
208 	putc((i>>8)&0xff,fp);
209 	putc(i&0xff,fp);
210 }
211 
212 #ifdef KLEMM_36
213 
Read24BitsHighLow(FILE * fp)214 int  Read24BitsHighLow ( FILE* fp )
215 {
216     int  high = ReadByte         (fp);
217     int  med  = ReadByteUnsigned (fp);
218     int  low  = ReadByteUnsigned (fp);
219 
220     return (high << 16) | (med << 8) | low;
221 }
222 
223 #else
224 int
Read24BitsHighLow(FILE * fp)225 Read24BitsHighLow(FILE *fp)
226 {
227 	int	first, second, third;
228 	int	result;
229 
230 	first = 0xff & getc(fp);
231 	second = 0xff & getc(fp);
232 	third = 0xff & getc(fp);
233 
234 	result = (first << 16) + (second << 8) + third;
235 	if (result & 0x800000)
236 		result = result - 0x1000000;
237 	return(result);
238 }
239 #endif
240 
241 #define	Read32BitsLowHigh(f)	Read32Bits(f)
242 
243 #ifdef KLEMM_36
244 
Read32Bits(FILE * fp)245 int  Read32Bits ( FILE* fp )
246 {
247     int  low  = ReadByteUnsigned (fp);
248     int  medl = ReadByteUnsigned (fp);
249     int  medh = ReadByteUnsigned (fp);
250     int  high = ReadByte         (fp);
251 
252     return (high << 24) | (medh << 16) | (medl << 8) | low;
253 }
254 
255 #else
256 
257 int
Read32Bits(FILE * fp)258 Read32Bits(FILE *fp)
259 {
260 	int	first, second, result;
261 
262 	first = 0xffff & Read16BitsLowHigh(fp);
263 	second = 0xffff & Read16BitsLowHigh(fp);
264 
265 	result = (second << 16) + first;
266 #ifdef	CRAY
267 	if (result & 0x80000000)
268 		result = result - 0x100000000;
269 #endif	/* CRAY */
270 	return(result);
271 }
272 #endif
273 
274 
275 #ifdef KLEMM_36
276 
Read32BitsHighLow(FILE * fp)277 int  Read32BitsHighLow ( FILE* fp )
278 {
279     int  high = ReadByte         (fp);
280     int  medh = ReadByteUnsigned (fp);
281     int  medl = ReadByteUnsigned (fp);
282     int  low  = ReadByteUnsigned (fp);
283 
284     return (high << 24) | (medh << 16) | (medl << 8) | low;
285 }
286 
287 #else
288 
289 int
Read32BitsHighLow(FILE * fp)290 Read32BitsHighLow(FILE *fp)
291 {
292 	int	first, second, result;
293 
294 	first = 0xffff & Read16BitsHighLow(fp);
295 	second = 0xffff & Read16BitsHighLow(fp);
296 
297 	result = (first << 16) + second;
298 #ifdef	CRAY
299 	if (result & 0x80000000)
300 		result = result - 0x100000000;
301 #endif
302 	return(result);
303 }
304 
305 #endif
306 
307 void
Write32Bits(FILE * fp,int i)308 Write32Bits(FILE *fp, int i)
309 {
310 	Write16BitsLowHigh(fp,(int)(i&0xffffL));
311 	Write16BitsLowHigh(fp,(int)((i>>16)&0xffffL));
312 }
313 
314 
315 void
Write32BitsLowHigh(FILE * fp,int i)316 Write32BitsLowHigh(FILE *fp, int i)
317 {
318 	Write16BitsLowHigh(fp,(int)(i&0xffffL));
319 	Write16BitsLowHigh(fp,(int)((i>>16)&0xffffL));
320 }
321 
322 
323 void
Write32BitsHighLow(FILE * fp,int i)324 Write32BitsHighLow(FILE *fp, int i)
325 {
326 	Write16BitsHighLow(fp,(int)((i>>16)&0xffffL));
327 	Write16BitsHighLow(fp,(int)(i&0xffffL));
328 }
329 
330 #ifdef KLEMM_36
ReadBytes(FILE * fp,char * p,int n)331 void ReadBytes (FILE     *fp, char *p, int n)
332 {
333     memset ( p, 0, n );
334     fread  ( p, 1, n, fp );
335 }
336 #else
ReadBytes(FILE * fp,char * p,int n)337 void ReadBytes(FILE	*fp, char *p, int n)
338 {
339 	/* What about fread? */
340 
341 	while (!feof(fp) & (n-- > 0))
342 		*p++ = getc(fp);
343 }
344 #endif
345 
ReadBytesSwapped(FILE * fp,char * p,int n)346 void ReadBytesSwapped(FILE *fp, char *p, int n)
347 {
348 	register char	*q = p;
349 
350 	/* What about fread? */
351 
352 	while (!feof(fp) & (n-- > 0))
353 		*q++ = getc(fp);
354 
355         /* If not all bytes could be read, the resorting is different
356 	 * from the normal resorting. Is this intention or another bug?
357 	 */
358 	for (q--; p < q; p++, q--){
359 		n = *p;
360 		*p = *q;
361 		*q = n;
362 	}
363 }
364 
365 #ifdef KLEMM_36
WriteBytes(FILE * fp,char * p,int n)366 void WriteBytes(FILE *fp, char *p, int n)
367 {
368     /* return n == */
369     fwrite ( p, 1, n, fp );
370 }
371 #else
WriteBytes(FILE * fp,char * p,int n)372 void WriteBytes(FILE *fp, char *p, int n)
373 {
374         /* No error condition checking */
375         while (n-- > 0)
376 		putc(*p++, fp);
377 }
378 #endif
379 #ifdef KLEMM_36
WriteBytesSwapped(FILE * fp,char * p,int n)380 void WriteBytesSwapped(FILE *fp, char *p, int n)
381 {
382     p += n;
383     while ( n-- > 0 )
384 	putc ( *--p, fp );
385 }
386 #else
WriteBytesSwapped(FILE * fp,char * p,int n)387 void WriteBytesSwapped(FILE *fp, char *p, int n)
388 {
389 	p += n-1;
390 	while (n-- > 0)
391 		putc(*p--, fp);
392 }
393 #endif
394 
395 
396 
397 /****************************************************************
398  * The following two routines make up for deficiencies in many
399  * compilers to convert properly between unsigned integers and
400  * floating-point.  Some compilers which have this bug are the
401  * THINK_C compiler for the Macintosh and the C compiler for the
402  * Silicon Graphics MIPS-based Iris.
403  ****************************************************************/
404 
405 #ifdef applec	/* The Apple C compiler works */
406 # define FloatToUnsigned(f)	((unsigned long)(f))
407 # define UnsignedToFloat(u)	((double)(u))
408 #else /* applec */
409 # define FloatToUnsigned(f)	((unsigned long)(((long)((f) - 2147483648.0)) + 2147483647L + 1))
410 # define UnsignedToFloat(u)	(((double)((long)((u) - 2147483647L - 1))) + 2147483648.0)
411 #endif /* applec */
412 /****************************************************************
413  * Extended precision IEEE floating-point conversion routines
414  ****************************************************************/
415 
416 double
ConvertFromIeeeExtended(char * bytes)417 ConvertFromIeeeExtended(char* bytes)
418 {
419 	double	f;
420 	long	expon;
421 	unsigned long hiMant, loMant;
422 
423 #ifdef	TEST
424 printf("ConvertFromIEEEExtended(%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx\r",
425 	(long)bytes[0], (long)bytes[1], (long)bytes[2], (long)bytes[3],
426 	(long)bytes[4], (long)bytes[5], (long)bytes[6],
427 	(long)bytes[7], (long)bytes[8], (long)bytes[9]);
428 #endif
429 
430 	expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
431 	hiMant	=	((unsigned long)(bytes[2] & 0xFF) << 24)
432 			|	((unsigned long)(bytes[3] & 0xFF) << 16)
433 			|	((unsigned long)(bytes[4] & 0xFF) << 8)
434 			|	((unsigned long)(bytes[5] & 0xFF));
435 	loMant	=	((unsigned long)(bytes[6] & 0xFF) << 24)
436 			|	((unsigned long)(bytes[7] & 0xFF) << 16)
437 			|	((unsigned long)(bytes[8] & 0xFF) << 8)
438 			|	((unsigned long)(bytes[9] & 0xFF));
439 
440         /* This case should also be called if the number is below the smallest
441 	 * positive double variable */
442 	if (expon == 0 && hiMant == 0 && loMant == 0) {
443 		f = 0;
444 	}
445 	else {
446 	        /* This case should also be called if the number is too large to fit into
447 		 * a double variable */
448 
449 		if (expon == 0x7FFF) {	/* Infinity or NaN */
450 			f = HUGE_VAL;
451 		}
452 		else {
453 			expon -= 16383;
454 			f  = ldexp(UnsignedToFloat(hiMant), (int) (expon -= 31));
455 			f += ldexp(UnsignedToFloat(loMant), (int) (expon -= 32));
456 		}
457 	}
458 
459 	if (bytes[0] & 0x80)
460 		return -f;
461 	else
462 		return f;
463 }
464 
465 
466 
467 
468 
469 double
ReadIeeeExtendedHighLow(FILE * fp)470 ReadIeeeExtendedHighLow(FILE *fp)
471 {
472 	char	bytes [10];
473 
474 	ReadBytes ( fp, bytes, 10 );
475 	return ConvertFromIeeeExtended ( bytes );
476 }
477 
478