]> 4ch.mooo.com Git - 16.git/blob - 16/adplug/libbinio-1.4/src/binio.cpp
Please enter the commit message for your changes. Lines starting
[16.git] / 16 / adplug / libbinio-1.4 / src / binio.cpp
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  * 
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  * Lesser General Public License for more details.
11  * 
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  *
16  * binio.cpp - Binary stream I/O classes
17  * Copyright (C) 2002, 2003 Simon Peter <dn.tlp@gmx.net>
18  */
19
20 #include <string.h>
21
22 #include "binio.h"
23
24 #if BINIO_WITH_MATH
25
26 #include <math.h>
27
28 #ifdef __QNXNTO__
29    #define pow std::powf
30 #endif // __QNXNTO__
31
32 // If 'math.h' doesn't define HUGE_VAL, we try to use HUGE instead.
33 #ifndef HUGE_VAL
34 # define HUGE_VAL HUGE
35 #endif
36
37 #endif
38
39 /***** Defines *****/
40
41 #if BINIO_ENABLE_STRING
42 // String buffer size for std::string readString() method
43 #define STRINGBUFSIZE   256
44 #endif
45
46 /***** binio *****/
47
48 const binio::Flags binio::system_flags = binio::detect_system_flags();
49
50 const binio::Flags binio::detect_system_flags()
51 {
52   Flags f = 0;
53
54   // Endian test
55   union {
56     int word;
57     Byte byte;
58   } endian_test;
59
60   endian_test.word = 1;
61   if(endian_test.byte != 1) f |= BigEndian;
62
63   // IEEE-754 floating-point test
64   float fl = 6.5;
65   Byte  *dat = (Byte *)&fl;
66
67   if(sizeof(float) == 4 && sizeof(double) == 8)
68     if(f & BigEndian) {
69       if(dat[0] == 0x40 && dat[1] == 0xD0 && !dat[2] && !dat[3])
70         f |= FloatIEEE;
71     } else
72       if(dat[3] == 0x40 && dat[2] == 0xD0 && !dat[1] && !dat[0])
73       f |= FloatIEEE;
74
75   return f;
76 }
77
78 binio::binio()
79   : my_flags(system_flags), err(NoError)
80 {
81 }
82
83 binio::~binio()
84 {
85 }
86
87 void binio::setFlag(Flag f, bool set)
88 {
89   if(set)
90     my_flags |= f;
91   else
92     my_flags &= !f;
93 }
94
95 bool binio::getFlag(Flag f)
96 {
97   return (my_flags & f ? true : false);
98 }
99
100 binio::Error binio::error()
101 {
102   Error e = err;
103
104   err = NoError;
105   return e;
106 }
107
108 bool binio::eof()
109 {
110   return (err & Eof ? true : false);
111 }
112
113 /***** binistream *****/
114
115 binistream::binistream()
116 {
117 }
118
119 binistream::~binistream()
120 {
121 }
122
123 binistream::Int binistream::readInt(unsigned int size)
124 {
125   unsigned int  i;
126   Int           val = 0, in;
127
128   // Check if 'size' doesn't exceed our system's biggest type.
129   if(size > sizeof(Int)) {
130     err |= Unsupported;
131     return 0;
132   }
133
134   for(i = 0; i < size; i++) {
135     in = getByte();
136     if(getFlag(BigEndian))
137       val <<= 8;
138     else
139       in <<= i * 8;
140     val |= in;
141   }
142
143   return val;
144 }
145
146 binistream::Float binistream::readFloat(FType ft)
147 {
148   if(getFlag(FloatIEEE)) {      // Read IEEE-754 floating-point value
149     unsigned int        i, size;
150     Byte                in[8];
151     bool                swap;
152
153     // Determine appropriate size for given type.
154     switch(ft) {
155     case Single: size = 4; break;       // 32 bits
156     case Double: size = 8; break;       // 64 bits
157     }
158
159     // Determine byte ordering, depending on what we do next
160     if(system_flags & FloatIEEE)
161       swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
162     else
163       swap = !getFlag(BigEndian);
164
165     // Read the float byte by byte, converting endianess
166     for(i = 0; i < size; i++)
167       if(swap)
168         in[size - i - 1] = getByte();
169       else
170         in[i] = getByte();
171
172     if(system_flags & FloatIEEE) {
173       // Compatible system, let the hardware do the conversion
174       switch(ft) {
175       case Single: return *(float *)in;
176       case Double: return *(double *)in;
177       }
178     } else {    // Incompatible system, convert manually
179       switch(ft) {
180       case Single: return ieee_single2float(in);
181       case Double: return ieee_double2float(in);
182       }
183     }
184   }
185
186   // User tried to read a (yet) unsupported floating-point type. Bail out.
187   err |= Unsupported; return 0.0;
188 }
189
190 binistream::Float binistream::ieee_single2float(Byte *data)
191 {
192   signed int    sign = data[0] >> 7 ? -1 : 1;
193   unsigned int  exp = ((data[0] << 1) & 0xff) | ((data[1] >> 7) & 1),
194     fracthi7 = data[1] & 0x7f;
195   Float         fract = fracthi7 * 65536.0 + data[2] * 256.0 + data[3];
196
197   // Signed and unsigned zero
198   if(!exp && !fracthi7 && !data[2] && !data[3]) return sign * 0.0;
199
200   // Signed and unsigned infinity (maybe unsupported on non-IEEE systems)
201   if(exp == 255)
202     if(!fracthi7 && !data[2] && !data[3]) {
203 #ifdef HUGE_VAL
204       if(sign == -1) return -HUGE_VAL; else return HUGE_VAL;
205 #else
206       err |= Unsupported;
207       if(sign == -1) return -1.0; else return 1.0;
208 #endif
209     } else {      // Not a number (maybe unsupported on non-IEEE systems)
210 #ifdef NAN
211       return NAN;
212 #else
213       err |= Unsupported; return 0.0;
214 #endif
215     }
216
217   if(!exp)      // Unnormalized float values
218     return sign * pow(2, -126) * fract * pow(2, -23);
219   else          // Normalized float values
220     return sign * pow(2, exp - 127) * (fract * pow(2, -23) + 1);
221
222   err |= Fatal; return 0.0;
223 }
224
225 binistream::Float binistream::ieee_double2float(Byte *data)
226 {
227   signed int    sign = data[0] >> 7 ? -1 : 1;
228   unsigned int  exp = ((unsigned int)(data[0] & 0x7f) << 4) | (data[1] >> 4),
229     fracthi4 = data[1] & 0xf;
230   Float         fract = fracthi4 * pow(2, 48) + data[2] * pow(2, 40) + data[3] *
231     pow(2, 32) + data[4] * pow(2, 24) + data[5] * pow(2, 16) + data[6] *
232     pow(2, 8) + data[7];
233
234   // Signed and unsigned zero
235   if(!exp && !fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] &&
236      !data[6] && !data[7]) return sign * 0.0;
237
238   // Signed and unsigned infinity  (maybe unsupported on non-IEEE systems)
239   if(exp == 2047)
240     if(!fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] && !data[6] &&
241        !data[7]) {
242 #ifdef HUGE_VAL
243       if(sign == -1) return -HUGE_VAL; else return HUGE_VAL;
244 #else
245       err |= Unsupported;
246       if(sign == -1) return -1.0; else return 1.0;
247 #endif
248     } else {      // Not a number (maybe unsupported on non-IEEE systems)
249 #ifdef NAN
250       return NAN;
251 #else
252       err |= Unsupported; return 0.0;
253 #endif
254     }
255
256   if(!exp)      // Unnormalized float values
257     return sign * pow(2, -1022) * fract * pow(2, -52);
258   else          // Normalized float values
259     return sign * pow(2, exp - 1023) * (fract * pow(2, -52) + 1);
260
261   err |= Fatal; return 0.0;
262 }
263
264 #if !BINIO_WITH_MATH
265 binio::Float binio::pow(Float base, signed int exp)
266 /* Our own, stripped-down version of pow() for not having to depend on 'math.h'.
267  * This one handles float values for the base and an integer exponent, both
268  * positive and negative.
269  */
270 {
271   int   i;
272   Float val = base;
273
274   if(!exp) return 1.0;
275
276   for(i = 1; i < (exp < 0 ? -exp : exp); i++)
277     val *= base;
278
279   if(exp < 0) val = 1.0 / val;
280
281   return val;
282 }
283 #endif
284
285 unsigned long binistream::readString(char *str, unsigned long maxlen)
286 {
287   unsigned long i;
288
289   for(i = 0; i < maxlen; i++) {
290     str[i] = (char)getByte();
291     if(err) { str[i] = '\0'; return i; }
292   }
293
294   return maxlen;
295 }
296
297 unsigned long binistream::readString(char *str, unsigned long maxlen,
298                                      const char delim)
299 {
300   unsigned long i;
301
302   for(i = 0; i < maxlen; i++) {
303     str[i] = (char)getByte();
304     if(str[i] == delim || err) { str[i] = '\0'; return i; }
305   }
306
307   str[maxlen] = '\0';
308   return maxlen;
309 }
310
311 #if BINIO_ENABLE_STRING
312 std::string binistream::readString(const char delim)
313 {
314   char buf[STRINGBUFSIZE + 1];
315   std::string tempstr;
316   unsigned long read;
317
318   do {
319     read = readString(buf, STRINGBUFSIZE, delim);
320     tempstr.append(buf, read);
321   } while(read == STRINGBUFSIZE);
322
323   return tempstr;
324 }
325 #endif
326
327 binistream::Int binistream::peekInt(unsigned int size)
328 {
329   Int val = readInt(size);
330   if(!err) seek(-(long)size, Add);
331   return val;
332 }
333
334 binistream::Float binistream::peekFloat(FType ft)
335 {
336   Float val = readFloat(ft);
337
338   if(!err)
339     switch(ft) {
340     case Single: seek(-4, Add); break;
341     case Double: seek(-8, Add); break;
342     }
343
344   return val;
345 }
346
347 bool binistream::ateof()
348 {
349   Error olderr = err;   // Save current error state
350   bool  eof_then;
351
352   peekInt(1);
353   eof_then = eof();     // Get error state of next byte
354   err = olderr;         // Restore original error state
355   return eof_then;
356 }
357
358 void binistream::ignore(unsigned long amount)
359 {
360   unsigned long i;
361
362   for(i = 0; i < amount; i++)
363     getByte();
364 }
365
366 /***** binostream *****/
367
368 binostream::binostream()
369 {
370 }
371
372 binostream::~binostream()
373 {
374 }
375
376 void binostream::writeInt(Int val, unsigned int size)
377 {
378   unsigned int  i;
379
380   // Check if 'size' doesn't exceed our system's biggest type.
381   if(size > sizeof(Int)) { err |= Unsupported; return; }
382
383   for(i = 0; i < size; i++) {
384     if(getFlag(BigEndian))
385       putByte((val >> (size - i - 1) * 8) & 0xff);
386     else {
387       putByte(val & 0xff);
388       val >>= 8;
389     }
390   }
391 }
392
393 void binostream::writeFloat(Float f, FType ft)
394 {
395   if(getFlag(FloatIEEE)) {      // Write IEEE-754 floating-point value
396     unsigned int        i, size;
397     Byte                *out;
398     bool                swap;
399
400     if(system_flags & FloatIEEE) {
401       // compatible system, let the hardware do the conversion
402       float     outf = f;
403       double    outd = f;
404
405       // Hardware could be big or little endian, convert appropriately
406       swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
407
408       // Determine appropriate size for given type and convert by hardware
409       switch(ft) {
410       case Single: size = 4; out = (Byte *)&outf; break;        // 32 bits
411       case Double: size = 8; out = (Byte *)&outd; break;        // 64 bits
412       }
413     } else {
414 #if BINIO_WITH_MATH
415       // incompatible system, do the conversion manually
416       Byte      buf[8];
417
418       // Our own value is always big endian, just check whether we have to
419       // convert for a different stream format.
420       swap = !getFlag(BigEndian);
421
422       // Convert system's float to requested IEEE-754 float
423       switch(ft) {
424       case Single: size = 4; float2ieee_single(f, buf); break;
425       case Double: size = 8; float2ieee_double(f, buf); break;
426       }
427
428       out = buf;        // Make the value ready for writing
429 #else
430       // No necessary support routines to do the conversion, bail out!
431       err |= Unsupported; return;
432 #endif
433     }
434
435     // Write the float byte by byte, converting endianess
436     if(swap) out += size - 1;
437     for(i = 0; i < size; i++) {
438       putByte(*out);
439       if(swap) out--; else out++;
440     }
441
442     return;     // We're done.
443   }
444
445   // User tried to write an unsupported floating-point type. Bail out.
446   err |= Unsupported;
447 }
448
449 #ifdef BINIO_WITH_MATH
450
451 /*
452  * Single and double floating-point to IEEE-754 equivalent conversion functions
453  * courtesy of Ken Turkowski.
454  *
455  * Copyright (C) 1989-1991 Ken Turkowski. <turk@computer.org>
456  *
457  * All rights reserved.
458  *
459  * Warranty Information
460  *  Even though I have reviewed this software, I make no warranty
461  *  or representation, either express or implied, with respect to this
462  *  software, its quality, accuracy, merchantability, or fitness for a
463  *  particular purpose.  As a result, this software is provided "as is,"
464  *  and you, its user, are assuming the entire risk as to its quality
465  *  and accuracy.
466  *
467  * This code may be used and freely distributed as long as it includes
468  * this copyright notice and the above warranty information.
469  */
470
471 /****************************************************************
472  * The following two routines make up for deficiencies in many
473  * compilers to convert properly between unsigned integers and
474  * floating-point.  Some compilers which have this bug are the
475  * THINK_C compiler for the Macintosh and the C compiler for the
476  * Silicon Graphics MIPS-based Iris.
477  ****************************************************************/
478
479 #ifdef applec   /* The Apple C compiler works */
480 # define FloatToUnsigned(f)     ((unsigned long)(f))
481 #else
482 # define FloatToUnsigned(f)     ((unsigned long)(((long)((f) - 2147483648.0)) + 2147483647L + 1))
483 #endif
484
485 #define SEXP_MAX        255
486 #define SEXP_OFFSET     127
487 #define SEXP_SIZE       8
488 #define SEXP_POSITION   (32-SEXP_SIZE-1)
489
490 void binostream::float2ieee_single(Float num, Byte *bytes)
491 {
492   long          sign;
493   register long bits;
494
495   if (num < 0) {        /* Can't distinguish a negative zero */
496     sign = 0x80000000;
497     num *= -1;
498   } else {
499     sign = 0;
500   }
501
502   if (num == 0) {
503     bits = 0;
504   } else {
505     Float       fMant;
506     int         expon;
507
508     fMant = frexp(num, &expon);
509
510     if ((expon > (SEXP_MAX-SEXP_OFFSET+1)) || !(fMant < 1)) {
511       /* NaN's and infinities fail second test */
512       bits = sign | 0x7F800000;         /* +/- infinity */
513     }
514
515     else {
516       long mantissa;
517
518       if (expon < -(SEXP_OFFSET-2)) {   /* Smaller than normalized */
519         int shift = (SEXP_POSITION+1) + (SEXP_OFFSET-2) + expon;
520         if (shift < 0) {        /* Way too small: flush to zero */
521           bits = sign;
522         }
523         else {                  /* Nonzero denormalized number */
524           mantissa = (long)(fMant * (1L << shift));
525           bits = sign | mantissa;
526         }
527       }
528
529       else {                            /* Normalized number */
530         mantissa = (long)floor(fMant * (1L << (SEXP_POSITION+1)));
531         mantissa -= (1L << SEXP_POSITION);                      /* Hide MSB */
532         bits = sign | ((long)((expon + SEXP_OFFSET - 1)) << SEXP_POSITION) | mantissa;
533       }
534     }
535   }
536
537   bytes[0] = bits >> 24;        /* Copy to byte string */
538   bytes[1] = bits >> 16;
539   bytes[2] = bits >> 8;
540   bytes[3] = bits;
541 }
542
543 #define DEXP_MAX        2047
544 #define DEXP_OFFSET     1023
545 #define DEXP_SIZE       11
546 #define DEXP_POSITION   (32-DEXP_SIZE-1)
547
548 void binostream::float2ieee_double(Float num, Byte *bytes)
549 {
550   long  sign;
551   long  first, second;
552
553   if (num < 0) {        /* Can't distinguish a negative zero */
554     sign = 0x80000000;
555     num *= -1;
556   } else {
557     sign = 0;
558   }
559
560   if (num == 0) {
561     first = 0;
562     second = 0;
563   } else {
564     Float       fMant, fsMant;
565     int         expon;
566
567     fMant = frexp(num, &expon);
568
569     if ((expon > (DEXP_MAX-DEXP_OFFSET+1)) || !(fMant < 1)) {
570       /* NaN's and infinities fail second test */
571       first = sign | 0x7FF00000;                /* +/- infinity */
572       second = 0;
573     }
574
575     else {
576       long mantissa;
577
578       if (expon < -(DEXP_OFFSET-2)) {   /* Smaller than normalized */
579         int shift = (DEXP_POSITION+1) + (DEXP_OFFSET-2) + expon;
580         if (shift < 0) {        /* Too small for something in the MS word */
581           first = sign;
582           shift += 32;
583           if (shift < 0) {      /* Way too small: flush to zero */
584             second = 0;
585           }
586           else {                        /* Pretty small demorn */
587             second = FloatToUnsigned(floor(ldexp(fMant, shift)));
588           }
589         }
590         else {                  /* Nonzero denormalized number */
591           fsMant = ldexp(fMant, shift);
592           mantissa = (long)floor(fsMant);
593           first = sign | mantissa;
594           second = FloatToUnsigned(floor(ldexp(fsMant - mantissa, 32)));
595         }
596       }
597
598       else {                            /* Normalized number */
599         fsMant = ldexp(fMant, DEXP_POSITION+1);
600         mantissa = (long)floor(fsMant);
601         mantissa -= (1L << DEXP_POSITION);                      /* Hide MSB */
602         fsMant -= (1L << DEXP_POSITION);
603         first = sign | ((long)((expon + DEXP_OFFSET - 1)) << DEXP_POSITION) | mantissa;
604         second = FloatToUnsigned(floor(ldexp(fsMant - mantissa, 32)));
605       }
606     }
607   }
608         
609   bytes[0] = first >> 24;
610   bytes[1] = first >> 16;
611   bytes[2] = first >> 8;
612   bytes[3] = first;
613   bytes[4] = second >> 24;
614   bytes[5] = second >> 16;
615   bytes[6] = second >> 8;
616   bytes[7] = second;
617 }
618
619 #endif // BINIO_WITH_MATH
620
621 unsigned long binostream::writeString(const char *str, unsigned long amount)
622 {
623   unsigned int i;
624
625   if(!amount) amount = strlen(str);
626
627   for(i = 0; i < amount; i++) {
628     putByte(str[i]);
629     if(err) return i;
630   }
631
632   return amount;
633 }
634
635 #if BINIO_ENABLE_STRING
636 unsigned long binostream::writeString(const std::string &str)
637 {
638   return writeString(str.c_str());
639 }
640 #endif