diff options
Diffstat (limited to 'src/zebra.c')
-rw-r--r-- | src/zebra.c | 242 |
1 files changed, 197 insertions, 45 deletions
diff --git a/src/zebra.c b/src/zebra.c index 4ce51a2..24973d7 100644 --- a/src/zebra.c +++ b/src/zebra.c @@ -10,6 +10,10 @@ char zebra_err[256]; zebraFile *zebra_open(const char *filename) { + /* Returns a pointer to a new zebra file object. + * + * Returns the pointer to the zebraFile object on success, or NULL on + * error. */ FILE *f = fopen(filename, "r"); if (!f) { @@ -18,16 +22,23 @@ zebraFile *zebra_open(const char *filename) } zebraFile *z = (zebraFile *) malloc(sizeof(zebraFile)); + + if (!z) { + sprintf(zebra_err, "failed to allocate space for zebraFile struct: %s", strerror(errno)); + fclose(f); + return NULL; + } + z->f = f; - z->offset = 0; z->lr_size = 0; z->buf = NULL; z->buf_size = 0; + z->tab = NULL; return z; } -int read_next_physical_record(zebraFile *z) +static int read_next_physical_record(zebraFile *z) { /* Read the next physical record from the zebra file and append it to the * buffer. @@ -94,7 +105,7 @@ int read_next_physical_record(zebraFile *z) return 0; } -int get_bytes(zebraFile *z, size_t size) +static int get_bytes(zebraFile *z, size_t size) { /* Read bytes from the zdab file until there are at least `size` words in * the buffer. @@ -102,7 +113,7 @@ int get_bytes(zebraFile *z, size_t size) * Returns 0 on success, -1 on error, and 1 on EOF. */ int rv; - while ((z->buf_size - z->offset) < size*4) { + while (z->buf_size < size*4) { rv = read_next_physical_record(z); if (rv == -1) { @@ -116,65 +127,189 @@ int get_bytes(zebraFile *z, size_t size) return 0; } -int read_next_logical_record(zebraFile *z) +static uint32_t get_link(zebraFile *z, uint32_t link) +{ + /* Returns the offset for a zebra bank in the local buffer from a link + * pointing to the original bank. */ + int i; + uint32_t sum; + + if (z->nwtab == 0) return link; + + sum = 0; + for (i = 0; i < z->nwtab/2; i++) { + if (link <= z->tab[i*2+1]) break; + sum += z->tab[i*2+1] - z->tab[i*2]; + } + + return sum + link - z->tab[i*2] + z->lr_offset; +} + +static int rewrite_links(zebraFile *z) +{ + /* Rewrite the next/up/orig, structural, and reference links for all banks + * in the current logical record. + * + * Returns 0 on success, -1 on error. */ + int i, rv; + uint32_t offset; + uint32_t io, noff; + zebraBank b; + + offset = z->lr_offset*4; + + while (offset < z->lr_size) { + io = unpacki32(z->buf+offset); + offset += 4; + + noff = io & 0xFFFF; + + if (noff > 12) { + offset += (noff - 12)*4; + } + + rv = zebra_get_bank(z, &b, offset/4); + + if (rv) return rv; + + /* Rewrite the next, up, and orig pointers. */ + if (b.next) + packi32(z->buf+offset,get_link(z,b.next)); + if (b.up) + packi32(z->buf+offset+4,get_link(z,b.up)); + if (b.orig) + packi32(z->buf+offset+8,get_link(z,b.orig)); + + /* Rewrite the structural and reference links. */ + for (i = 0; i < b.num_links; i++) { + if (b.links[i]) + packi32(z->buf+offset-(i+1)*4,get_link(z,b.links[i])); + } + + offset += 9*4; + + offset += b.num_data_words*4; + } + + return 0; +} + +int zebra_read_next_logical_record(zebraFile *z) { /* Read the next logical record into the buffer. * * Returns 0 on success, -1 on error, and 1 on EOF. */ + int i; uint32_t size, type, nwtx, nwseg, nwtab, nwuh; + uint32_t io, noff; + uint32_t offset; while (1) { - memmove(z->buf,z->buf+z->offset,z->buf_size-z->offset); - z->buf = realloc(z->buf, z->buf_size-z->offset); - z->buf_size -= z->offset; - z->offset = 0; + /* Move the next logical record to the start of the buffer. */ + memmove(z->buf,z->buf+z->lr_size,z->buf_size-z->lr_size); + z->buf = realloc(z->buf, z->buf_size-z->lr_size); + z->buf_size -= z->lr_size; + offset = 0; - switch (get_bytes(z,1)) { + switch (get_bytes(z,offset+1)) { case 1: return 1; case -1: return -1; } - size = unpacki32(z->buf+z->offset); - z->offset += 4; - + size = unpacki32(z->buf+offset*4); + offset += 1; + + /* If the size of the logical record is zero, we just skip it. + * + * From page 142 of the ZEBRA document at + * https://cdsweb.cern.ch/record/2296399/files/zebra.pdf: + * + * "The total size of a padding record is NWLR+1, including the LR + * length and the LR type; thus a padding record with NWLR=1 occupies + * two words. To pad exactly one word, NWLR=0 should be stored, in this + * case the LR type 5 is implied without being present in the data." */ if (size == 0) continue; - switch (get_bytes(z,1)) { + switch (get_bytes(z,offset+1)) { case 1: return 1; case -1: return -1; } - type = unpacki32(z->buf+z->offset); - z->offset += 4; + + /* Get the logical record type. */ + type = unpacki32(z->buf+offset*4); + offset += 1; switch (type) { + /* Padding records. */ case 5: case 6: - get_bytes(z,size-1); - z->offset += (size-1)*4; + get_bytes(z,offset+size-1); + z->lr_size = (size + 1)*4; continue; + /* Start or end of run. */ case 1: - get_bytes(z,size); - z->offset += size*4; + get_bytes(z,offset+size); + z->lr_size = (size + 2)*4; continue; + /* Normal records. */ + case 2: + case 3: + case 4: + break; } + /* For normal records the size of the logical record is NWLR + the two + * words for the size and type. */ z->lr_size = (size + 2)*4; - get_bytes(z,size); + get_bytes(z,offset+size); + + nwtx = unpacki32(z->buf+(offset+4)*4); + nwseg = unpacki32(z->buf+(offset+5)*4); + nwtab = unpacki32(z->buf+(offset+6)*4); + nwuh = unpacki32(z->buf+(offset+9)*4); - nwtx = unpacki32(z->buf+z->offset+4*4); - nwseg = unpacki32(z->buf+z->offset+5*4); - nwtab = unpacki32(z->buf+z->offset+6*4); - nwuh = unpacki32(z->buf+z->offset+9*4); + if (nwtab % 2) { + sprintf(zebra_err, "number of words in relocation table is not a multiple of 2!"); + return -1; + } - z->offset += 10*4; + offset += 10; - z->offset += nwtx*4; - z->offset += nwseg*4; - z->offset += nwtab*4; - z->offset += nwuh*4; + /* Currently we don't use the user header, segment table, or the text + * vector. */ + offset += nwuh; + offset += nwseg; + offset += nwtx; + + /* Read the relocation table. */ + if (z->tab) free(z->tab); + z->tab = malloc(sizeof(double)*nwtab); + for (i = 0; i < nwtab; i++) + z->tab[i] = unpacki32(z->buf+(offset+i)*4); + z->nwtab = nwtab; + offset += nwtab; + + z->lr_offset = offset; + + /* Find the pointer to the first bank. */ + io = unpacki32(z->buf+offset*4); + + noff = io & 0xFFFF; + + /* First bank is just past the end of the logical record (one word for + * the io control word). */ + z->first_bank = offset + 1; + + /* Skip the links to get to the bank's next pointer. */ + if (noff > 12) { + z->first_bank += noff - 12; + } + + /* Rewrite the next/up/orig, structural, and reference links. */ + if (rewrite_links(z)) return -1; break; } @@ -182,31 +317,47 @@ int read_next_logical_record(zebraFile *z) return 0; } -int next_bank(zebraFile *z, bank *b) +int zebra_get_bank(zebraFile *z, zebraBank *b, uint32_t link) { - int rv; - uint32_t io, noff; + /* Get the bank located at `link`. + * + * On success 0 is returned and the zebraBank struct `b` is filled with the + * bank information. On error, -1 is returned and zebra_err is set. */ + int i; - if (z->offset == z->lr_size) { - rv = read_next_logical_record(z); - if (rv) return rv; + if ((link+9)*4 > z->buf_size) { + sprintf(zebra_err, "link location of %i is outside buffer!", link); + return -1; } - io = unpacki32(z->buf+z->offset); - z->offset += 4; + unpack(z->buf+link*4,"lllllllll",&b->next, &b->up, &b->orig, &b->number, &b->idh, &b->num_links, &b->num_structural_links, &b->num_data_words, &b->status); + + unpack(z->buf+link*4+16,"cccc",b->name,b->name+1,b->name+2,b->name+3); - noff = io & 0xFFFF; + b->name[4] = '\0'; - if (noff > 12) { - z->offset += (noff-12)*4; + if (b->num_links > MAX_LINKS) { + sprintf(zebra_err, "number of links in bank is greater than %i!", MAX_LINKS); + return -1; + } + + if (link < b->num_links) { + sprintf(zebra_err, "buffer only has %i words before bank, not enough for %i links!", link, b->num_links); + return -1; } - unpack(z->buf+z->offset,"lllllllll",&b->next, &b->up, &b->orig, &b->number, &b->name, &b->num_links, &b->num_structural_links, &b->num_data_words, &b->status); - z->offset += 9*4; + /* Read in reference and structural links. */ + for (i = 0; i < b->num_links; i++) + b->links[i] = unpacki32(z->buf+(link-1-i)*4); - b->data = (uint32_t *) (z->buf+z->offset); + link += 9; + + if ((link+b->num_data_words)*4 > z->buf_size) { + sprintf(zebra_err, "bank contains %i data bytes, but there are only %zu bytes left in buffer!", b->num_data_words*4, z->buf_size-link*4); + return -1; + } - z->offset += b->num_data_words*4; + b->data = (uint32_t *) (z->buf+link*4); return 0; } @@ -214,6 +365,7 @@ int next_bank(zebraFile *z, bank *b) void zebra_close(zebraFile *z) { fclose(z->f); + if (z->tab) free(z->tab); if (z->buf) free(z->buf); free(z); } |