Octopus
io_binary.c
Go to the documentation of this file.
1/*
2 Copyright (C) 2006 X. Andrade
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18
19*/
20
21/*
22
23The functions in this file write and read an array to binary file.
24
25*/
26
27#define _FILE_OFFSET_BITS 64
28
29#include <assert.h>
30#include <config.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <math.h>
34#include <stdint.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <unistd.h>
41
42#include "io_binary.h"
44typedef char byte;
46static const int64_t size_of[6] = {4, 8, 8, 16, 4, 8};
47static const int64_t base_size_of[6] = {4, 8, 4, 8, 4, 8};
48static const int64_t is_integer[6] = {0, 0, 0, 0, 1, 1};
49
50static inline void inf_error(const char *msg) {
51 perror(msg);
52}
53
54typedef union {
55 float f[2];
56 double d[2];
57} multi;
58
59/* A very basic endian conversion routine. This can be improved a lot,
60 but it is not necessary, as restart files are converted at most
61 once per run */
62
63static inline void endian_convert(const int size, char *aa) {
64 char tmp[8];
65 int ii;
66
67 for (ii = 0; ii < size; ii++)
68 tmp[ii] = aa[ii];
69 for (ii = 0; ii < size; ii++)
70 aa[ii] = tmp[size - 1 - ii];
71}
72
73static void convert(multi *in, multi *out, int t_in, int t_out);
74
75/* how to convert a complex to a real */
76#define c2r hypot /* take the modulus */
77
78/* THE HEADER OF THE FILE */
79typedef struct {
80 /* text to identify the file */
81 char text[7]; /*7 bytes*/
82
83 /* version of the format */
84 uint8_t version; /* 8 bytes*/
85
86 /* value of 1 in different formats, to recognize endianness */
87 uint32_t one_32; /*12 bytes */
88 float one_f; /* 16 bytes*/
89 uint64_t one_64; /* 24 bytes */
90 double one_d; /* 32 bytes */
91
92 /* the size of the array stored */
93 uint64_t np; /* 40 bytes */
94
95 /* the type of the wfs */
96 uint32_t type; /* 44 bytes */
97
98 /* extra values for future versions*/
99 uint32_t extra[5]; /* 64 bytes */
100
101} header_t;
102
103static inline void init_header(header_t *hp) {
104 int ii;
105
106 strcpy(hp->text, "pulpo");
107
108 hp->text[6] = 0;
109 hp->version = 0;
110 hp->one_32 = 1;
111 hp->one_f = 1.0;
112 hp->one_64 = 1;
113 hp->one_d = 1.0;
114
115 for (ii = 0; ii < 5; ii++)
116 hp->extra[ii] = 0;
117}
118
119static inline int check_header(header_t *hp, int *correct_endianness) {
120 if (strcmp("pulpo", hp->text) != 0)
121 return 5;
122 if (hp->version != 0)
123 return 5;
124
125 /* Check the endianness of integer values and fix header
126 components */
127
128 if (hp->one_32 != 1) {
129 endian_convert(4, (char *)&(hp->one_32));
130 if (hp->one_32 != 1)
131 return 5;
132 endian_convert(4, (char *)&(hp->type));
133 }
134
135 if (hp->one_64 != 1) {
136 endian_convert(8, (char *)&(hp->one_64));
137 if (hp->one_64 != 1)
138 return 5;
139 endian_convert(8, (char *)&(hp->np));
140 }
141
142 /* Check the endianness of floating point values */
143 *correct_endianness = 0;
144 if (base_size_of[hp->type] == 4) {
145 if (hp->one_f != 1.0) {
146 endian_convert(4, (char *)&(hp->one_f));
147 if (hp->one_f != 1.0)
148 return 5;
149 *correct_endianness = 1;
150 }
151 } else {
152 if (hp->one_d != 1.0) {
153 endian_convert(8, (char *)&(hp->one_d));
154 if (hp->one_d != 1.0)
155 return 5;
156 *correct_endianness = 1;
157 }
158 }
159
160 return 0;
161}
162
163void io_write_header(const int64_t *np, int *type, int *ierr, int *iio,
164 char *fname) {
165 header_t *hp;
166 int fd;
167 ssize_t moved;
169 hp = (header_t *)malloc(sizeof(header_t));
170 assert(hp != NULL);
171 assert(np > 0);
173 *ierr = 0;
174 fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC,
175 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
176 *iio += 100;
177 if (fd < 0) {
178 printf("Filename is %s\n", fname);
179 inf_error("octopus.write_header in creating the header");
180 *ierr = 2;
181 free(hp);
182 return;
183 }
184
185 /* create header */
186 init_header(hp);
187 hp->np = *np;
188 hp->type = *type;
189
190 /* write header */
191 moved = write(fd, hp, sizeof(header_t));
192
193 if (moved < sizeof(header_t)) {
194 /* we couldn't write the complete header */
195 inf_error("octopus.write_header in writing the header");
196 *ierr = 3;
199 free(hp);
200 close(fd);
201 *iio += 1;
203
204void write_binary(const int64_t *np, void *ff, int *type, int *ierr, int *iio,
205 int *nhd, int *flpe, char *fname) {
206 int fd;
208 ssize_t moved;
209 ssize_t bytes_to_write;
210 ssize_t offset;
211
212 assert(np > 0);
213 *ierr = 0;
214
215 if (*nhd != 1) {
216 io_write_header(np, type, ierr, iio, fname);
218
219 fd = open(fname, O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
220 iio += 100;
221 if (fd < 0) {
222 inf_error("octopus.write_binary in opening the file");
223 *ierr = 2;
224 return;
225 }
226
227 /* skip the header and go until the end */
228 lseek(fd, 0, SEEK_END);
229
230 /* flip endianness*/
231 if (*flpe == 1) {
232 for (ii = 0; ii < (*np) * size_of[(*type)]; ii += base_size_of[(*type)])
233 endian_convert(base_size_of[(*type)], (char *)(ff + ii));
234 }
236 /* now write the values */
237 bytes_to_write = (*np) * size_of[(*type)];
238 offset = 0;
239 while (bytes_to_write > 0) {
240 moved = write(fd, ff + offset, bytes_to_write);
241 if (moved < 0) {
242 /* an error occurred */
243 inf_error("octopus.write_binary in actual writing");
244 *ierr = 3;
245 break;
247 bytes_to_write -= moved;
248 offset += moved;
249 }
250
251 /* close the file */
252 close(fd);
253 iio++;
254 return;
255}
256
257/* this function neither allocates nor deallocates 'hp' */
258void io_read_header(header_t *hp, int *correct_endianness, int *ierr, int *iio,
259 char *fname) {
260 int fd;
261 ssize_t moved;
262
263 *ierr = 0;
264 fd = open(fname, O_RDONLY);
265 *iio += 100;
266 if (fd < 0) {
267 *ierr = 2;
268 return;
269 }
270
271 assert(hp != NULL);
272
273 /* read header */
274 moved = read(fd, hp, sizeof(header_t));
275 if (moved != sizeof(header_t)) {
276 /* we couldn't read the complete header */
277 *ierr = 3;
278 return;
279 }
280
281 *ierr = check_header(hp, correct_endianness);
282 if (*ierr != 0) {
283 return;
284 }
285
286 close(fd);
287 (*iio)++;
288}
289
290void read_binary(const int64_t *np, const int64_t *offset, byte *ff,
291 int *output_type, int *ierr, int *iio, char *fname) {
292 header_t *hp;
293 int fd;
294 int64_t ii;
295 ssize_t moved;
296 int correct_endianness;
297 byte *read_f;
298
299 assert(np > 0);
300
301 /* read the header */
302 hp = (header_t *)malloc(sizeof(header_t));
303 assert(hp != NULL);
304 io_read_header(hp, &correct_endianness, ierr, iio, fname);
305 if (*ierr != 0) {
306 free(hp);
307 return;
308 }
309
310 /* check whether the sizes match */
311 if (hp->np < *np + *offset) {
312 *ierr = 4;
313 free(hp);
314 return;
315 }
317 fd = open(fname, O_RDONLY);
318 *iio += 100;
319
320 if (fd < 0) {
321 *ierr = 2;
322 free(hp);
323 return;
324 }
325
326 if (hp->type == *output_type) {
327 /* format is the same, we just read */
328 read_f = ff;
329 } else {
330 /*format is not the same, we store into a temporary array */
331 read_f = (byte *)malloc((*np) * size_of[hp->type]);
334 /* set the start point */
335 if (*offset != 0)
336 lseek(fd, (*offset) * size_of[hp->type] + sizeof(header_t), SEEK_SET);
337 else
338 lseek(fd, sizeof(header_t), SEEK_SET);
339
340 /* now read the values and close the file */
341 moved = read(fd, read_f, (*np) * size_of[hp->type]);
343 close(fd);
344 (*iio)++;
345
346 if (moved != (*np) * size_of[hp->type]) {
347 /* we couldn't read the whole dataset */
348 *ierr = 3;
349 if (hp->type != *output_type) {
350 free(read_f);
352 free(hp);
353 return;
355
356 /* convert endianness */
357
358 if (correct_endianness) {
359 for (ii = 0; ii < (*np) * size_of[hp->type]; ii += base_size_of[hp->type])
360 endian_convert(base_size_of[hp->type], (char *)(read_f + ii));
361 }
363 /* convert values if it is necessary */
364 if (hp->type != *output_type) {
366 if (is_integer[hp->type] || is_integer[*output_type]) {
367 *ierr = 5;
368 } else {
369
370 for (ii = 0; ii < *np; ii++)
371 convert((multi *)(read_f + ii * size_of[hp->type]),
372 (multi *)(ff + ii * size_of[*output_type]), hp->type,
373 *output_type);
374
375 /* set the error code according to the conversion done (see
376 * src/basic/io_binary.h) */
377 if (hp->type == TYPE_FLOAT)
378 *ierr = -1;
379 if (hp->type == TYPE_FLOAT_COMPLEX)
380 *ierr = -2;
381 if (hp->type == TYPE_DOUBLE)
382 *ierr = -3;
383 if (hp->type == TYPE_DOUBLE_COMPLEX)
384 *ierr = -4;
385 }
386 free(read_f);
387 }
388
389 free(hp);
390}
391
392/*
393 This function converts between types.
394*/
395
396static void convert(multi *in, multi *out, int t_in, int t_out) {
397
398 /* real types */
399 if (t_in == TYPE_FLOAT && t_out == TYPE_DOUBLE) {
400 out->d[0] = in->f[0];
401 return;
402 }
403
404 if (t_in == TYPE_DOUBLE && t_out == TYPE_FLOAT) {
405 out->f[0] = in->d[0];
406 return;
407 }
408
409 /* complex types */
410 if (t_in == TYPE_FLOAT_COMPLEX && t_out == TYPE_DOUBLE_COMPLEX) {
411 out->d[0] = in->f[0];
412 out->d[1] = in->f[1];
413 return;
414 }
415 if (t_in == TYPE_DOUBLE_COMPLEX && t_out == TYPE_FLOAT_COMPLEX) {
416 out->f[0] = in->d[0];
417 out->f[1] = in->d[1];
418 return;
420
421 /* real to complex */
422 if (t_in == TYPE_FLOAT && t_out == TYPE_FLOAT_COMPLEX) {
423 out->f[0] = in->f[0];
424 out->f[1] = (float)0.0;
425 return;
426 }
427
428 if (t_in == TYPE_DOUBLE && t_out == TYPE_FLOAT_COMPLEX) {
429 out->f[0] = in->d[0];
430 out->f[1] = (float)0.0;
431 return;
432 }
434 if (t_in == TYPE_FLOAT && t_out == TYPE_DOUBLE_COMPLEX) {
435 out->d[0] = in->f[0];
436 out->d[1] = (double)0.0;
437 return;
439
440 if (t_in == TYPE_DOUBLE && t_out == TYPE_DOUBLE_COMPLEX) {
441 out->d[0] = in->d[0];
442 out->d[1] = (double)0.0;
443 return;
444 }
445
446 /* complex to real */
447 if (t_in == TYPE_FLOAT_COMPLEX && t_out == TYPE_FLOAT) {
448 out->f[0] = c2r(in->f[0], in->f[1]);
449 return;
451
452 if (t_in == TYPE_DOUBLE_COMPLEX && t_out == TYPE_FLOAT) {
453 out->f[0] = c2r(in->d[0], in->d[1]);
454 return;
455 }
456
457 if (t_in == TYPE_FLOAT_COMPLEX && t_out == TYPE_DOUBLE) {
458 out->d[0] = c2r(in->f[0], in->f[1]);
459 return;
461
462 if (t_in == TYPE_DOUBLE_COMPLEX && t_out == TYPE_DOUBLE) {
463 out->d[0] = c2r(in->d[0], in->d[1]);
464 return;
465 }
466}
468void get_info_binary(int64_t *np, int *type, int64_t *file_size, int *ierr,
469 int *iio, char *fname) {
470 header_t *hp;
471 int correct_endianness;
472 struct stat st;
473
474 hp = (header_t *)malloc(sizeof(header_t));
475 assert(hp != NULL);
477 /* read header */
478 io_read_header(hp, &correct_endianness, ierr, iio, fname);
479
480 if (*ierr == 0) {
481 *np = hp->np;
482 *type = (int)hp->type;
483 } else {
484 *np = 0;
485 *type = TYPE_NONE;
487 free(hp);
488
489 stat(fname, &st);
490 *file_size = (int64_t)st.st_size;
491}
__ssize_t ssize_t
Definition: getopt_f.c:317
either version
Definition: global.h:11
__uint32_t uint32_t
Definition: io_binary.c:1336
static void convert(multi *in, multi *out, int t_in, int t_out)
Definition: io_binary.c:5131
void get_info_binary(int64_t *np, int *type, int64_t *file_size, int *ierr, int *iio, char *fname)
Definition: io_binary.c:5203
__uint8_t uint8_t
Definition: io_binary.c:1334
static int check_header(header_t *hp, int *correct_endianness)
Definition: io_binary.c:4682
void io_write_header(const int64_t *np, int *type, int *ierr, int *iio, char *fname)
Definition: io_binary.c:4726
__uint64_t uint64_t
Definition: io_binary.c:1337
__int64_t int64_t
Definition: io_binary.c:1328
static const int64_t base_size_of[6]
Definition: io_binary.c:4610
static const int64_t is_integer[6]
Definition: io_binary.c:4611
void read_binary(const int64_t *np, const int64_t *offset, byte *ff, int *output_type, int *ierr, int *iio, char *fname)
Definition: io_binary.c:4981
static void init_header(header_t *hp)
Definition: io_binary.c:4666
static void endian_convert(const int size, char *aa)
Definition: io_binary.c:4626
void io_read_header(header_t *hp, int *correct_endianness, int *ierr, int *iio, char *fname)
Definition: io_binary.c:4929
void write_binary(const int64_t *np, void *ff, int *type, int *ierr, int *iio, int *nhd, int *flpe, char *fname)
Definition: io_binary.c:4831
static void inf_error(const char *msg)
Definition: io_binary.c:4613
int open(const char *__file, int __oflag,...) __asm__("" "open64") __attribute__((__nonnull__(1)))
character(len=512), private msg
Definition: messages.F90:165
integer, parameter in
Definition: pes_mask.F90:258
integer, parameter out
Definition: pes_mask.F90:258
integer, parameter fd
Definition: run.F90:167
int stat(const char *__restrict __file, struct stat *__restrict __buf) __attribute__((__nothrow__
uint32_t one_32
Definition: io_binary.c:4650
double one_d
Definition: io_binary.c:4653
uint32_t extra[5]
Definition: io_binary.c:4662
float one_f
Definition: io_binary.c:4651
char text[7]
Definition: io_binary.c:4644
uint64_t one_64
Definition: io_binary.c:4652
uint8_t version
Definition: io_binary.c:4647
uint64_t np
Definition: io_binary.c:4656
uint32_t type
Definition: io_binary.c:4659