/* Copyright (c) 2019, Anthony Latorre * * 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 . */ /* 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 /* for FILE */ #include /* for size_t */ #include /* for uint8_t, etc. */ #include /* 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