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