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