ARTS  2.0.49
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 {
53  Flags f = 0;
54 
55  // Endian test
56  union {
57  int word;
58  Byte byte;
59  } endian_test;
60 
61  endian_test.word = 1;
62  if(endian_test.byte != 1) f |= BigEndian;
63 
64  // IEEE-754 floating-point test
65  float fl = 6.5f;
66  Byte *dat = (Byte *)&fl;
67 
68  if(sizeof(float) == 4 && sizeof(double) == 8)
69  {
70  if(f & BigEndian)
71  {
72  if(dat[0] == 0x40 && dat[1] == 0xD0 && !dat[2] && !dat[3])
73  f |= FloatIEEE;
74  }
75  else
76  {
77  if(dat[3] == 0x40 && dat[2] == 0xD0 && !dat[1] && !dat[0])
78  f |= FloatIEEE;
79  }
80  }
81 
82  return f;
83 }
84 
86  : my_flags(system_flags), err(NoError)
87 {
88 }
89 
91 {
92 }
93 
94 void binio::setFlag(Flag f, bool set)
95 {
96  if(set)
97  my_flags |= f;
98  else
99  my_flags &= !f;
100 }
101 
103 {
104  return (my_flags & f ? true : false);
105 }
106 
108 {
109  Error e = err;
110 
111  err = NoError;
112  return e;
113 }
114 
116 {
117  return (err & Eof ? true : false);
118 }
119 
120 /***** binistream *****/
121 
123 {
124 }
125 
127 {
128 }
129 
131 {
132  unsigned int i;
133  Int val = 0, in;
134 
135  // Check if 'size' doesn't exceed our system's biggest type.
136  if(size > sizeof(Int)) {
137  err |= Unsupported;
138  throw runtime_error ("The size of the integer to be read exceeds our system's biggest type");
139  return 0;
140  }
141 
142  for(i = 0; i < size; i++) {
143  in = getByte();
144  if(getFlag(BigEndian))
145  val <<= 8;
146  else
147  in <<= i * 8;
148  val |= in;
149  }
150 
151  return val;
152 }
153 
155 {
156  if(getFlag(FloatIEEE))
157  {
158  // Read IEEE-754 floating-point value
159 
160  unsigned int i=0;
161  unsigned int size=0;
162  Byte in[8];
163  bool swap;
164 
165  // Determine appropriate size for given type.
166  switch(ft) {
167  case Single: size = 4; break; // 32 bits
168  case Double: size = 8; break; // 64 bits
169  }
170 
171  // Determine byte ordering, depending on what we do next
172  if(system_flags & FloatIEEE)
173  swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
174  else
175  swap = !getFlag(BigEndian);
176 
177  if (!swap && ((size == sizeof (float)) || (size == sizeof (double))))
178  {
179  if (size == 4)
180  {
181  float f;
182  getRaw ((char *)&f, size);
183  return (Float)f;
184  }
185  else
186  {
187  double d;
188  getRaw ((char *)&d, size);
189  return (Float)d;
190  }
191  }
192  else
193  {
194  // Read the float byte by byte, converting endianess
195  for(i = 0; i < size; i++)
196  if(swap)
197  in[size - i - 1] = getByte();
198  else
199  in[i] = getByte();
200 
201  if(system_flags & FloatIEEE) {
202  // Compatible system, let the hardware do the conversion
203  switch(ft) {
204  case Single: return *(float *)in;
205  case Double: return *(double *)in;
206  }
207  } else { // Incompatible system, convert manually
208  switch(ft) {
209  case Single: return ieee_single2float(in);
210  case Double: return ieee_double2float(in);
211  }
212  }
213  }
214  }
215 
216  // User tried to read a (yet) unsupported floating-point type. Bail out.
217  err |= Unsupported; return 0.0;
218 }
219 
221 {
222  signed int sign = data[0] >> 7 ? -1 : 1;
223  unsigned int exp = ((data[0] << 1) & 0xff) | ((data[1] >> 7) & 1),
224  fracthi7 = data[1] & 0x7f;
225  Float fract = fracthi7 * 65536.0 + data[2] * 256.0 + data[3];
226 
227  // Signed and unsigned zero
228  if(!exp && !fracthi7 && !data[2] && !data[3]) return sign * 0.0;
229 
230  // Signed and unsigned infinity (maybe unsupported on non-IEEE systems)
231  if(exp == 255)
232  {
233  if(!fracthi7 && !data[2] && !data[3])
234  {
235 #ifdef HUGE_VAL
236  if(sign == -1) return -HUGE_VAL; else return HUGE_VAL;
237 #else
238  err |= Unsupported;
239  if(sign == -1) return -1.0; else return 1.0;
240 #endif
241  }
242  else
243  { // Not a number (maybe unsupported on non-IEEE systems)
244 #ifdef NAN
245  return NAN;
246 #else
247  err |= Unsupported; return 0.0;
248 #endif
249  }
250  }
251 
252  if(!exp) // Unnormalized float values
253  return sign * pow(2, -126.) * fract * pow(2, -23.);
254  else // Normalized float values
255  return sign * pow(2, exp - 127.) * (fract * pow(2, -23.) + 1);
256 
257  err |= Fatal; return 0.0;
258 }
259 
261 {
262  signed int sign = data[0] >> 7 ? -1 : 1;
263  unsigned int exp = ((unsigned int)(data[0] & 0x7f) << 4) | (data[1] >> 4),
264  fracthi4 = data[1] & 0xf;
265  Float fract = fracthi4 * pow(2, 48.) + data[2] * pow(2, 40.) + data[3] *
266  pow(2, 32.) + data[4] * pow(2, 24.) + data[5] * pow(2, 16.) + data[6] *
267  pow(2, 8.) + data[7];
268 
269  // Signed and unsigned zero
270  if(!exp && !fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] &&
271  !data[6] && !data[7]) return sign * 0.0;
272 
273  // Signed and unsigned infinity (maybe unsupported on non-IEEE systems)
274  if(exp == 2047)
275  {
276  if(!fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] && !data[6] &&
277  !data[7])
278  {
279 #ifdef HUGE_VAL
280  if(sign == -1) return -HUGE_VAL; else return HUGE_VAL;
281 #else
282  err |= Unsupported;
283  if(sign == -1) return -1.0; else return 1.0;
284 #endif
285  }
286  else
287  { // Not a number (maybe unsupported on non-IEEE systems)
288 #ifdef NAN
289  return NAN;
290 #else
291  err |= Unsupported; return 0.0;
292 #endif
293  }
294  }
295 
296  if(!exp) // Unnormalized float values
297  return sign * pow(2, -1022.) * fract * pow(2, -52.);
298  else // Normalized float values
299  return sign * pow(2, exp - 1023.) * (fract * pow(2, -52.) + 1);
300 
301  err |= Fatal; return 0.0;
302 }
303 
304 #if !BINIO_WITH_MATH
305 binio::Float binio::pow(Float base, signed int exp)
306 /* Our own, stripped-down version of pow() for not having to depend on 'math.h'.
307  * This one handles float values for the base and an integer exponent, both
308  * positive and negative.
309  */
310 {
311  int i;
312  Float val = base;
313 
314  if(!exp) return 1.0;
315 
316  for(i = 1; i < (exp < 0 ? -exp : exp); i++)
317  val *= base;
318 
319  if(exp < 0) val = 1.0 / val;
320 
321  return val;
322 }
323 #endif
324 
325 unsigned long binistream::readString(char *str, unsigned long maxlen)
326 {
327  unsigned long i;
328 
329  for(i = 0; i < maxlen; i++) {
330  str[i] = (char)getByte();
331  if(err) { str[i] = '\0'; return i; }
332  }
333 
334  return maxlen;
335 }
336 
337 unsigned long binistream::readString(char *str, unsigned long maxlen,
338  const char delim)
339 {
340  unsigned long i;
341 
342  for(i = 0; i < maxlen; i++) {
343  str[i] = (char)getByte();
344  if(str[i] == delim || err) { str[i] = '\0'; return i; }
345  }
346 
347  str[maxlen] = '\0';
348  return maxlen;
349 }
350 
351 #if BINIO_ENABLE_STRING
352 std::string binistream::readString(const char delim)
353 {
354  char buf[STRINGBUFSIZE + 1];
355  std::string tempstr;
356  unsigned long read;
357 
358  do {
359  read = readString(buf, STRINGBUFSIZE, delim);
360  tempstr.append(buf, read);
361  } while(read == STRINGBUFSIZE);
362 
363  return tempstr;
364 }
365 #endif
366 
368 {
369  Int val = readInt(size);
370  if(!err) seek(-(long)size, Add);
371  return val;
372 }
373 
375 {
376  Float val = readFloat(ft);
377 
378  if(!err)
379  switch(ft) {
380  case Single: seek(-4, Add); break;
381  case Double: seek(-8, Add); break;
382  }
383 
384  return val;
385 }
386 
388 {
389  Error olderr = err; // Save current error state
390  bool eof_then;
391 
392  peekInt(1);
393  eof_then = eof(); // Get error state of next byte
394  err = olderr; // Restore original error state
395  return eof_then;
396 }
397 
398 void binistream::ignore(unsigned long amount)
399 {
400  unsigned long i;
401 
402  for(i = 0; i < amount; i++)
403  getByte();
404 }
405 
406 /***** binostream *****/
407 
409 {
410 }
411 
413 {
414 }
415 
416 void binostream::writeInt(Int val, unsigned int size)
417 {
418  unsigned int i;
419 
420  // Check if 'size' doesn't exceed our system's biggest type.
421  if(size > sizeof(Int)) {
422  err |= Unsupported;
423  throw runtime_error ("The size of the integer to be stored exceeds our system's biggest type");
424  return;
425  }
426 
427  for(i = 0; i < size; i++) {
428  if(getFlag(BigEndian))
429  putByte((unsigned char)(val >> ((size - i - 1) * 8)) & 0xff);
430  else {
431  putByte((unsigned char)val & 0xff);
432  val >>= 8;
433  }
434  }
435 }
436 
438 {
439  if(getFlag(FloatIEEE)) { // Write IEEE-754 floating-point value
440 
441  unsigned int i=0;
442  unsigned int size=0;
443  Byte *out=NULL;
444  bool swap;
445 
446  if(system_flags & FloatIEEE) {
447  // compatible system, let the hardware do the conversion
448  float outf = (float)f;
449  double outd = (double)f;
450 
451  // Hardware could be big or little endian, convert appropriately
452  swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
453 
454  switch(ft) {
455  case Single: size = 4; break; // 32 bits
456  case Double: size = 8; break; // 64 bits
457  }
458 
459  if (!swap && ((size == sizeof (float)) || (size == sizeof (double))))
460  {
461  if (size == 4)
462  { putRaw ((char *)&outf, size); return; }
463  else
464  { putRaw ((char *)&outd, size); return; }
465  }
466  else
467  {
468  // Determine appropriate size for given type and convert by hardware
469  switch(ft) {
470  case Single: out = (Byte *)&outf; break; // 32 bits
471  case Double: out = (Byte *)&outd; break; // 64 bits
472  }
473  }
474  } else {
475 #if BINIO_WITH_MATH
476  // incompatible system, do the conversion manually
477  Byte buf[8];
478 
479  // Our own value is always big endian, just check whether we have to
480  // convert for a different stream format.
481  swap = !getFlag(BigEndian);
482 
483  // Convert system's float to requested IEEE-754 float
484  switch(ft) {
485  case Single: size = 4; float2ieee_single(f, buf); break;
486  case Double: size = 8; float2ieee_double(f, buf); break;
487  }
488 
489  out = buf; // Make the value ready for writing
490 #else
491  // No necessary support routines to do the conversion, bail out!
492  err |= Unsupported; return;
493 #endif
494  }
495 
496  // Write the float byte by byte, converting endianess
497  if(swap) out += size - 1;
498  for(i = 0; i < size; i++) {
499  putByte(*out);
500  if(swap) out--; else 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) ((unsigned long)(((long)((f) - 2147483648.0)) + 2147483647L + 1))
544 #endif
545 
546 #define SEXP_MAX 255
547 #define SEXP_OFFSET 127
548 #define SEXP_SIZE 8
549 #define SEXP_POSITION (32-SEXP_SIZE-1)
550 
552 {
553  long sign;
554  register 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  }
584  else { /* Nonzero denormalized number */
585  mantissa = (long)(fMant * (double)(1L << shift));
586  bits = sign | mantissa;
587  }
588  }
589 
590  else { /* Normalized number */
591  mantissa = (long)floor(fMant * (1L << (SEXP_POSITION+1)));
592  mantissa -= (1L << SEXP_POSITION); /* Hide MSB */
593  bits = sign | ((long)((expon + SEXP_OFFSET - 1)) << SEXP_POSITION) | 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 {
611  long sign;
612  long first, second;
613 
614  if (num < 0) { /* Can't distinguish a negative zero */
615  sign = 0x80000000;
616  num *= -1;
617  } else {
618  sign = 0;
619  }
620 
621  if (num == 0) {
622  first = 0;
623  second = 0;
624  } else {
625  Float fMant, fsMant;
626  int expon;
627 
628  fMant = frexp(num, &expon);
629 
630  if ((expon > (DEXP_MAX-DEXP_OFFSET+1)) || !(fMant < 1)) {
631  /* NaN's and infinities fail second test */
632  first = sign | 0x7FF00000; /* +/- infinity */
633  second = 0;
634  }
635 
636  else {
637  long mantissa;
638 
639  if (expon < -(DEXP_OFFSET-2)) { /* Smaller than normalized */
640  int shift = (DEXP_POSITION+1) + (DEXP_OFFSET-2) + expon;
641  if (shift < 0) { /* Too small for something in the MS word */
642  first = sign;
643  shift += 32;
644  if (shift < 0) { /* Way too small: flush to zero */
645  second = 0;
646  }
647  else { /* Pretty small demorn */
648  second = FloatToUnsigned(floor(ldexp(fMant, shift)));
649  }
650  }
651  else { /* Nonzero denormalized number */
652  fsMant = ldexp(fMant, shift);
653  mantissa = (long)floor(fsMant);
654  first = sign | mantissa;
655  second = FloatToUnsigned(floor(ldexp(fsMant - (double)mantissa, 32)));
656  }
657  }
658 
659  else { /* Normalized number */
660  fsMant = ldexp(fMant, DEXP_POSITION+1);
661  mantissa = (long)floor(fsMant);
662  mantissa -= (1L << DEXP_POSITION); /* Hide MSB */
663  fsMant -= (1L << DEXP_POSITION);
664  first = sign | ((long)((expon + DEXP_OFFSET - 1)) << DEXP_POSITION) | mantissa;
665  second = FloatToUnsigned(floor(ldexp(fsMant - (double)mantissa, 32)));
666  }
667  }
668  }
669 
670  bytes[0] = (unsigned char)(first >> 24);
671  bytes[1] = (unsigned char)(first >> 16);
672  bytes[2] = (unsigned char)(first >> 8);
673  bytes[3] = (unsigned char)first;
674  bytes[4] = (unsigned char)(second >> 24);
675  bytes[5] = (unsigned char)(second >> 16);
676  bytes[6] = (unsigned char)(second >> 8);
677  bytes[7] = (unsigned char)second;
678 }
679 
680 #endif // BINIO_WITH_MATH
681 
682 unsigned long binostream::writeString(const char *str, unsigned long amount)
683 {
684  unsigned int i;
685 
686  if(!amount) amount = strlen(str);
687 
688  for(i = 0; i < amount; i++) {
689  putByte(str[i]);
690  if(err) return i;
691  }
692 
693  return amount;
694 }
695 
696 #if BINIO_ENABLE_STRING
697 unsigned long binostream::writeString(const std::string &str)
698 {
699  return writeString(str.c_str());
700 }
701 #endif
binistream::peekFloat
Float peekFloat(FType ft)
Definition: binio.cc:374
binistream::readString
unsigned long readString(char *str, unsigned long amount)
Definition: binio.cc:325
binio::BigEndian
@ BigEndian
Definition: binio.h:70
SEXP_MAX
#define SEXP_MAX
Definition: binio.cc:546
binostream::float2ieee_double
void float2ieee_double(Float f, Byte *data)
Definition: binio.cc:609
FloatToUnsigned
#define FloatToUnsigned(f)
Definition: binio.cc:543
binio::err
Error err
Definition: binio.h:109
binio::FloatIEEE
@ FloatIEEE
Definition: binio.h:71
sign
Numeric sign(const Numeric &x)
sign
Definition: math_funcs.cc:473
binio::Fatal
@ Fatal
Definition: binio.h:76
binio::FType
FType
Definition: binio.h:85
binio::binio
binio()
Definition: binio.cc:85
binio::Flags
int Flags
Definition: binio.h:105
binio::Flag
Flag
Definition: binio.h:69
binistream::~binistream
virtual ~binistream()
Definition: binio.cc:126
binio::Add
@ Add
Definition: binio.h:84
binio.h
binostream::writeFloat
void writeFloat(Float f, FType ft)
Definition: binio.cc:437
binostream::writeInt
void writeInt(Int val, unsigned int size)
Definition: binio.cc:416
binistream::ignore
void ignore(unsigned long amount=1)
Definition: binio.cc:398
binio::seek
virtual void seek(long, Offset=Set)=0
binio::Float
double Float
Definition: binio.h:102
binio::Unsupported
@ Unsupported
Definition: binio.h:77
binio::Int
long Int
Definition: binio.h:101
binio::getFlag
bool getFlag(Flag f)
Definition: binio.cc:102
HUGE_VAL
#define HUGE_VAL
Definition: binio.cc:35
binostream::putByte
virtual void putByte(Byte)=0
binistream::peekInt
Int peekInt(unsigned int size)
Definition: binio.cc:367
binistream::ieee_double2float
Float ieee_double2float(Byte *data)
Definition: binio.cc:260
DEXP_POSITION
#define DEXP_POSITION
Definition: binio.cc:607
SEXP_POSITION
#define SEXP_POSITION
Definition: binio.cc:549
binio::NoError
@ NoError
Definition: binio.h:75
binistream::getByte
virtual Byte getByte()=0
DEXP_OFFSET
#define DEXP_OFFSET
Definition: binio.cc:605
binio::my_flags
Flags my_flags
Definition: binio.h:107
binio::detect_system_flags
static Flags detect_system_flags()
Definition: binio.cc:51
binostream::putRaw
virtual void putRaw(const char *c, streamsize n)=0
binio::error
Error error()
Definition: binio.cc:107
binio::system_flags
static const Flags system_flags
Definition: binio.h:108
binistream::ieee_single2float
Float ieee_single2float(Byte *data)
Definition: binio.cc:220
binistream::getRaw
virtual void getRaw(char *c, streamsize n)=0
binio::Single
@ Single
Definition: binio.h:85
binistream::binistream
binistream()
Definition: binio.cc:122
binostream::~binostream
virtual ~binostream()
Definition: binio.cc:412
binio::eof
bool eof()
Definition: binio.cc:115
binostream::binostream
binostream()
Definition: binio.cc:408
binio::setFlag
void setFlag(Flag f, bool set=true)
Definition: binio.cc:94
binio::Error
int Error
Definition: binio.h:86
binostream::writeString
unsigned long writeString(const char *str, unsigned long amount=0)
Definition: binio.cc:682
STRINGBUFSIZE
#define STRINGBUFSIZE
Definition: binio.cc:44
SEXP_OFFSET
#define SEXP_OFFSET
Definition: binio.cc:547
binistream::ateof
bool ateof()
Definition: binio.cc:387
DEXP_MAX
#define DEXP_MAX
Definition: binio.cc:604
binistream::readInt
Int readInt(unsigned int size)
Definition: binio.cc:130
binistream::readFloat
Float readFloat(FType ft)
Definition: binio.cc:154
binio::Byte
unsigned char Byte
Definition: binio.h:103
binio::Eof
@ Eof
Definition: binio.h:81
binostream::float2ieee_single
void float2ieee_single(Float f, Byte *data)
Definition: binio.cc:551
binio::~binio
virtual ~binio()
Definition: binio.cc:90
binio::Double
@ Double
Definition: binio.h:85