ARTS  2.3.1285(git:92a29ea9-dirty)
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 
81 
83 
84 void binio::setFlag(Flag f, bool set) {
85  if (set)
86  my_flags |= f;
87  else
88  my_flags &= !f;
89 }
90 
91 bool binio::getFlag(Flag f) { return (my_flags & f ? true : false); }
92 
94  Error e = err;
95 
96  err = NoError;
97  return e;
98 }
99 
100 bool 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
152  if (system_flags & FloatIEEE)
153  swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
154  else
155  swap = !getFlag(BigEndian);
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
291 binio::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 
310 unsigned 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 
324 unsigned 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
342 std::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 
387 void 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 
399 void 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
434  swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
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.
471  swap = !getFlag(BigEndian);
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 
680 unsigned 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
694 unsigned long binostream::writeString(const std::string &str) {
695  return writeString(str.c_str());
696 }
697 #endif
unsigned char Byte
Definition: binio.h:99
virtual ~binio()
Definition: binio.cc:82
Flag
Definition: binio.h:68
FType
Definition: binio.h:81
binio()
Definition: binio.cc:80
Error err
Definition: binio.h:105
void read(HitranRelaxationMatrixData &hitran, ArrayOfAbsorptionLines &bands, 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.
double Float
Definition: binio.h:98
#define SEXP_POSITION
Definition: binio.cc:550
bool getFlag(Flag f)
Definition: binio.cc:91
Float ieee_single2float(Byte *data)
Definition: binio.cc:199
virtual void seek(long, Offset=Set)=0
#define DEXP_OFFSET
Definition: binio.cc:605
virtual ~binostream()
Definition: binio.cc:397
binostream()
Definition: binio.cc:395
long Int
Definition: binio.h:97
#define DEXP_MAX
Definition: binio.cc:604
G0 G2 FVC Y DV Numeric Numeric Numeric Zeeman LowerQuantumNumbers void * data
unsigned long writeString(const char *str, unsigned long amount=0)
Definition: binio.cc:680
Numeric sign(const Numeric &x)
sign
Definition: math_funcs.cc:423
void swap(ComplexVector &v1, ComplexVector &v2)
Swaps two objects.
Definition: complex.cc:731
Float readFloat(FType ft)
Definition: binio.cc:132
binistream()
Definition: binio.cc:104
void float2ieee_single(Float f, Byte *data)
Definition: binio.cc:552
#define SEXP_OFFSET
Definition: binio.cc:548
Float peekFloat(FType ft)
Definition: binio.cc:362
unsigned long readString(char *str, unsigned long amount)
Definition: binio.cc:310
Int readInt(unsigned int size)
Definition: binio.cc:108
bool ateof()
Definition: binio.cc:377
Error error()
Definition: binio.cc:93
static const Flags system_flags
Definition: binio.h:104
void float2ieee_double(Float f, Byte *data)
Definition: binio.cc:609
Flags my_flags
Definition: binio.h:103
Numeric pow(const Rational base, Numeric exp)
Power of.
Definition: rational.h:628
bool eof()
Definition: binio.cc:100
void writeFloat(Float f, FType ft)
Definition: binio.cc:420
int Error
Definition: binio.h:82
void writeInt(Int val, unsigned int size)
Definition: binio.cc:399
void ignore(unsigned long amount=1)
Definition: binio.cc:387
static Flags detect_system_flags()
Definition: binio.cc:51
#define FloatToUnsigned(f)
Definition: binio.cc:543
void setFlag(Flag f, bool set=true)
Definition: binio.cc:84
Float ieee_double2float(Byte *data)
Definition: binio.cc:242
#define HUGE_VAL
Definition: binio.cc:35
#define SEXP_MAX
Definition: binio.cc:547
virtual ~binistream()
Definition: binio.cc:106
Int peekInt(unsigned int size)
Definition: binio.cc:356
#define STRINGBUFSIZE
Definition: binio.cc:44
#define DEXP_POSITION
Definition: binio.cc:607
int Flags
Definition: binio.h:101