ARTS 2.5.11 (git: 6827797f)
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#include "debug.h"
25
26/***** Defines *****/
27
28#if BINIO_ENABLE_STRING
29// String buffer size for std::string readString() method
30#define STRINGBUFSIZE 256
31#endif
32
33/***** binio *****/
34
36
38 Flags f = 0;
39
40 // Endian test
41 union {
42 int word;
43 Byte byte;
44 } endian_test;
45
46 endian_test.word = 1;
47 if (endian_test.byte != 1) f |= BigEndian;
48
49 // IEEE-754 floating-point test
50 float fl = 6.5f;
51 Byte *dat = (Byte *)&fl;
52
53 if (sizeof(float) == 4 && sizeof(double) == 8) {
54 if (f & BigEndian) {
55 if (dat[0] == 0x40 && dat[1] == 0xD0 && !dat[2] && !dat[3])
56 f |= FloatIEEE;
57 } else {
58 if (dat[3] == 0x40 && dat[2] == 0xD0 && !dat[1] && !dat[0])
59 f |= FloatIEEE;
60 }
61 }
62
63 return f;
64}
65
67 if (!(system_flags & FloatIEEE)) {
69 "IEEE floating-point numbers are not supported on "
70 "this system.");
71 }
72
73 // Set Little Endian mode, with IEEE-754 floats.
74 this->setFlag(binio::BigEndian, false); // remove flag
75 this->setFlag(binio::FloatIEEE); // set flag
76}
77
78void binio::setFlag(Flag f, bool set) {
79 if (set)
80 my_flags |= f;
81 else
82 my_flags &= !f;
83}
84
85bool binio::getFlag(Flag f) { return (my_flags & f ? true : false); }
86
88 Error e = err;
89
90 err = NoError;
91 return e;
92}
93
94bool binio::eof() { return (err & Eof ? true : false); }
95
96/***** binistream *****/
98 unsigned int i;
99 Int val = 0, in;
100
101 // Check if 'size' doesn't exceed our system's biggest type.
102 if (size > sizeof(Int)) {
103 err |= Unsupported;
104 throw runtime_error(
105 "The size of the integer to be read exceeds our system's biggest type");
106 return 0;
107 }
108
109 for (i = 0; i < size; i++) {
110 in = getByte();
111 if (getFlag(BigEndian))
112 val <<= 8;
113 else
114 in <<= i * 8;
115 val |= in;
116 }
117
118 return val;
119}
120
122 unsigned int i = 0;
123 unsigned int size = 0;
124 Byte in[8];
125 bool swap;
126
127 // Determine appropriate size for given type.
128 switch (ft) {
129 case Single:
130 size = 4;
131 break; // 32 bits
132 case Double:
133 size = 8;
134 break; // 64 bits
135 }
136
137 // Determine byte ordering, depending on what we do next
138 swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
139
140 if (!swap && ((size == sizeof(float)) || (size == sizeof(double)))) {
141 if (size == 4) {
142 float f;
143 getRaw((char *)&f, size);
144 return (Float)f;
145 }
146
147 double d;
148 getRaw((char *)&d, size);
149 return (Float)d;
150 }
151
152 // Read the float byte by byte, converting endianess
153 for (i = 0; i < size; i++)
154 if (swap)
155 in[size - i - 1] = getByte();
156 else
157 in[i] = getByte();
158
159 // Compatible system, let the hardware do the conversion
160 switch (ft) {
161 case Single:
162 return *(float *)in;
163 case Double:
164 return *(double *)in;
165 }
166
167 // User tried to read a (yet) unsupported floating-point type. Bail out.
168 ARTS_USER_ERROR("Unsupported floating-point type");
169}
170
171void swap_endian(double *d) {
172 auto *val = reinterpret_cast<uint64_t *>(d);
173 // Using this is much faster than swapping bytes manually
174 *val = ((((*val) >> 56) & 0x00000000000000FF) |
175 (((*val) >> 40) & 0x000000000000FF00) |
176 (((*val) >> 24) & 0x0000000000FF0000) |
177 (((*val) >> 8) & 0x00000000FF000000) |
178 (((*val) << 8) & 0x000000FF00000000) |
179 (((*val) << 24) & 0x0000FF0000000000) |
180 (((*val) << 40) & 0x00FF000000000000) |
181 (((*val) << 56) & 0xFF00000000000000));
182}
183
184void binistream::readDoubleArray(double *d, unsigned long size) {
185 getRaw((char *)d, sizeof(double) * size);
186
187 const bool swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
188 if (swap)
189 for (double *dptr = d; dptr < d + size; dptr++) swap_endian(dptr);
190}
191
192unsigned long binistream::readString(char *str, unsigned long maxlen) {
193 unsigned long i;
194
195 for (i = 0; i < maxlen; i++) {
196 str[i] = (char)getByte();
197 if (err) {
198 str[i] = '\0';
199 return i;
200 }
201 }
202
203 return maxlen;
204}
205
206unsigned long binistream::readString(char *str,
207 unsigned long maxlen,
208 const char delim) {
209 unsigned long i;
210
211 for (i = 0; i < maxlen; i++) {
212 str[i] = (char)getByte();
213 if (str[i] == delim || err) {
214 str[i] = '\0';
215 return i;
216 }
217 }
218
219 str[maxlen] = '\0';
220 return maxlen;
221}
222
223#if BINIO_ENABLE_STRING
224std::string binistream::readString(const char delim) {
225 char buf[STRINGBUFSIZE + 1];
226 std::string tempstr;
227 unsigned long read;
228
229 do {
230 read = readString(buf, STRINGBUFSIZE, delim);
231 tempstr.append(buf, read);
232 } while (read == STRINGBUFSIZE);
233
234 return tempstr;
235}
236#endif
237
239 Int val = readInt(size);
240 if (!err) seek(-(long)size, Add);
241 return val;
242}
243
245 Float val = readFloat(ft);
246
247 if (!err) switch (ft) {
248 case Single:
249 seek(-4, Add);
250 break;
251 case Double:
252 seek(-8, Add);
253 break;
254 }
255
256 return val;
257}
258
260 Error olderr = err; // Save current error state
261 bool eof_then;
262
263 peekInt(1);
264 eof_then = eof(); // Get error state of next byte
265 err = olderr; // Restore original error state
266 return eof_then;
267}
268
269void binistream::ignore(unsigned long amount) {
270 unsigned long i;
271
272 for (i = 0; i < amount; i++) getByte();
273}
274
275/***** binostream *****/
276
277void binostream::writeInt(Int val, unsigned int size) {
278 unsigned int i;
279
280 // Check if 'size' doesn't exceed our system's biggest type.
281 if (size > sizeof(Int)) {
282 err |= Unsupported;
283 throw runtime_error(
284 "The size of the integer to be stored exceeds our system's biggest type");
285 return;
286 }
287
288 for (i = 0; i < size; i++) {
289 if (getFlag(BigEndian))
290 putByte((unsigned char)(val >> ((size - i - 1) * 8)) & 0xff);
291 else {
292 putByte((unsigned char)val & 0xff);
293 val >>= 8;
294 }
295 }
296}
297
299 unsigned int i = 0;
300 unsigned int size = 0;
301 Byte *out = nullptr;
302 bool swap;
303
304 auto outf = (float)f;
305 auto outd = (double)f;
306
307 // Hardware could be big or little endian, convert appropriately
308 swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
309
310 switch (ft) {
311 case Single:
312 size = 4;
313 break; // 32 bits
314 case Double:
315 size = 8;
316 break; // 64 bits
317 }
318
319 if (!swap && ((size == sizeof(float)) || (size == sizeof(double)))) {
320 if (size == 4) {
321 putRaw((char *)&outf, size);
322 return;
323 }
324
325 putRaw((char *)&outd, size);
326 return;
327 }
328 // Determine appropriate size for given type and convert by hardware
329 switch (ft) {
330 case Single:
331 out = (Byte *)&outf;
332 break; // 32 bits
333 case Double:
334 out = (Byte *)&outd;
335 break; // 64 bits
336 }
337
338 // Write the float byte by byte, converting endianess
339 if (swap) out += size - 1;
340 for (i = 0; i < size; i++) {
341 putByte(*out);
342 if (swap)
343 out--;
344 else
345 out++;
346 }
347
348 return; // We're done.
349}
350
351unsigned long binostream::writeString(const char *str, unsigned long amount) {
352 unsigned int i;
353
354 if (!amount) amount = strlen(str);
355
356 for (i = 0; i < amount; i++) {
357 putByte(str[i]);
358 if (err) return i;
359 }
360
361 return amount;
362}
363
364#if BINIO_ENABLE_STRING
365unsigned long binostream::writeString(const std::string &str) {
366 return writeString(str.c_str());
367}
368#endif
void swap_endian(double *d)
Definition: binio.cc:171
void setFlag(Flag f, bool set=true)
Definition: binio.cc:78
std::int64_t Int
Definition: binio.h:80
Error error()
Definition: binio.cc:87
bool eof()
Definition: binio.cc:94
virtual void seek(long, Offset=Set)=0
static Flags detect_system_flags()
Definition: binio.cc:37
bool getFlag(Flag f)
Definition: binio.cc:85
int Error
Definition: binio.h:66
static const Flags system_flags
Definition: binio.h:87
enum { BigEndian=1<< 0, FloatIEEE=1<< 1 } Flag
Definition: binio.h:52
unsigned char Byte
Definition: binio.h:82
enum { Single, Double } FType
Definition: binio.h:65
int Flags
Definition: binio.h:84
double Float
Definition: binio.h:81
Flags my_flags
Definition: binio.h:86
binio()
Definition: binio.cc:66
Error err
Definition: binio.h:88
bool ateof()
Definition: binio.cc:259
unsigned long readString(char *str, unsigned long amount)
Definition: binio.cc:192
virtual Byte getByte()=0
Float peekFloat(FType ft)
Definition: binio.cc:244
void ignore(unsigned long amount=1)
Definition: binio.cc:269
Int readInt(unsigned int size)
Definition: binio.cc:97
virtual void getRaw(char *c, std::streamsize n)=0
Int peekInt(unsigned int size)
Definition: binio.cc:238
Float readFloat(FType ft)
Definition: binio.cc:121
void readDoubleArray(double *d, unsigned long size)
Definition: binio.cc:184
void writeInt(Int val, unsigned int size)
Definition: binio.cc:277
virtual void putRaw(const char *c, std::streamsize n)=0
virtual void putByte(Byte)=0
unsigned long writeString(const char *str, unsigned long amount=0)
Definition: binio.cc:351
void writeFloat(Float f, FType ft)
Definition: binio.cc:298
Helper macros for debugging.
#define ARTS_USER_ERROR(...)
Definition: debug.h:151
#define d