1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
/* Copyright (c) 2019, Anthony Latorre <tlatorre at uchicago>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
/* Library for reading ZEBRA files.
*
* The ZEBRA file format is an old file format used by FORTRAN programs for
* memory management and storing data structures. In particular, it's the
* default file format used by SNOMAN.
*
* This library is fairly simple and almost certainly does *not* include all
* the details needed to read an arbitrary ZEBRA file. Instead I implemented as
* much as was necessary to read in SNOMAN files and fixed bugs along the way.
*
* Example usage:
*
* zebraBank b;
* zebraFile *z = zebra_open("Muons.zdab")
*
* while (1) {
* rv = read_next_logical_record(z);
*
* switch (rv) {
* case 1:
* // EOF
* goto end;
* case -1:
* fprintf(stderr, "error getting logical record: %s\n", zebra_err);
* goto err;
* }
*
* zebra_get_bank(z,&b,z->first_bank);
*
* // etc.
* }
*
*/
#ifndef ZEBRA_H
#define ZEBRA_H
#include <stdio.h> /* for FILE */
#include <stdlib.h> /* for size_t */
#include <stdint.h> /* for uint8_t, etc. */
#include <zlib.h> /* for gzFile */
/* Maximum number of links in a bank.
*
* Technically we could malloc() this but that means we would have to free
* banks which would be annoying. */
#define MAX_LINKS 100
/* Global error string when any function returns -1. */
extern char zebra_err[256];
/* Physical record markers. */
#define ZEBRA_SIG0 0x0123cdefUL
#define ZEBRA_SIG1 0x80708070UL
#define ZEBRA_SIG2 0x4321abcdUL
#define ZEBRA_SIG3 0x80618061UL
/* Bitmasks for the physical record block size control word. */
#define ZEBRA_BLOCK_SIZE_MASK 0x00ffffffUL
#define ZEBRA_EMERGENCY_STOP 0x80000000UL
#define ZEBRA_END_OF_RUN 0x20000000UL
#define ZEBRA_START_OF_RUN 0x40000000UL
typedef struct zebraBank {
/* Pointer to the next bank in the chain. */
uint32_t next;
/* Pointer to the supporting bank. */
uint32_t up;
/* Pointer to the previous bank in the chain (or to the referencing link in
* the supporting bank if it's the first). */
uint32_t orig;
/* Bank number. From the SNOMAN FAQ:
*
* "In general, ZEBRA attaches no special significance to the bank number,
* and it is perfectly O.K. to change it at any time." */
uint32_t number;
/* Hollerith bank ID as an integer. */
uint32_t idh;
/* Total number of links in the bank.
*
* Note: In SNOMAN reference links aren't guaranteed to point to the start
* of a bank. According to the SNOMAN docs all reference links in SNOMAN
* should point to the bank's status word instead of the start of the bank,
* but I tried the following and it didn't seem to work:
*
* zebra_get_bank(z,&b,mctk.links[KMCTK_MCVX-1]-8);
*
* So, I'm not really sure how reference links work in SNOMAN. */
uint32_t num_links;
/* Number of structural links. The order of the links in the bank is:
*
* structural link 1
* structural link 2
* ...
* structural link num_structural_links
* reference link num_structural_links+1
* reference link num_structural_links+2
* ...
* reference link num_links
*
*/
uint32_t num_structural_links;
/* Number of data words. */
uint32_t num_data_words;
/* Status word. */
uint32_t status;
/* Pointer to the bank data in zebraFile->buf. Note that after calling
* zebra_read_next_logical_record(), this pointer will no longer point to
* the bank data. */
uint32_t *data;
/* Reference and structural links. */
uint32_t links[MAX_LINKS];
/* The Hollerith bank name as a string instead of an integer. This can be
* useful when printing error messages or for debugging. */
char name[5];
} zebraBank;
typedef struct zebraFile {
gzFile f;
/* Size of the current logical record in bytes. */
size_t lr_size;
/* Buffer used to read in the zebra file. */
uint8_t *buf;
/* Total size of the current buffer. */
size_t buf_size;
/* Relocation table. */
uint32_t *tab;
/* Number of words in the relocation table. */
size_t nwtab;
/* Link to first bank. */
uint32_t first_bank;
/* Link to the MAST bank. */
int32_t mast_bank;
/* Number of words from the start of the buffer to the first bank word. */
uint32_t lr_offset;
} zebraFile;
zebraFile *zebra_open(const char *filename);
int zebra_read_next_logical_record(zebraFile *z);
int zebra_get_bank(zebraFile *z, zebraBank *b, uint32_t link);
void zebra_close(zebraFile *z);
#endif
|