#include "reader.h"
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
static int readBTLF(struct READER *reader, struct BTREE *btree,
int number_of_records, union RECORD *records) {
int i;
uint8_t type, message_flags;
uint32_t creation_order, hash_of_name;
uint64_t heap_id;
char buf[5];
UNUSED(heap_id);
UNUSED(hash_of_name);
UNUSED(creation_order);
UNUSED(message_flags);
if (mysofa_read(reader, buf, 4) != 4 || strncmp(buf, "BTLF", 4)) {
mylog("cannot read signature of BTLF\n"); return MYSOFA_INVALID_FORMAT; }
buf[4] = 0;
mylog("%08" PRIX64 " %.4s\n", (uint64_t)mysofa_tell(reader) - 4, buf);
if (mysofa_getc(reader) != 0) {
mylog("object BTLF must have version 0\n"); return MYSOFA_INVALID_FORMAT; }
type = (uint8_t)mysofa_getc(reader);
for (i = 0; i < number_of_records; i++) {
switch (type) {
case 5:
records->type5.hash_of_name = (uint32_t)readValue(reader, 4);
records->type5.heap_id = readValue(reader, 7);
mylog(" type5 %08X %14" PRIX64 "\n", records->type5.hash_of_name,
records->type5.heap_id);
records++;
break;
case 6:
readValue(reader, 8);
readValue(reader, 7);
break;
case 8:
readValue(reader, 8);
mysofa_getc(reader);
readValue(reader, 4);
readValue(reader, 4);
break;
case 9:
readValue(reader, 8);
mysofa_getc(reader);
readValue(reader, 4);
break;
default:
mylog("object BTLF has unknown type %d\n", type);
return MYSOFA_INVALID_FORMAT;
}
}
return MYSOFA_OK;
}
int btreeRead(struct READER *reader, struct BTREE *btree) {
char buf[5];
if (mysofa_read(reader, buf, 4) != 4 || strncmp(buf, "BTHD", 4)) {
mylog("cannot read signature of BTHD\n");
return MYSOFA_INVALID_FORMAT;
}
buf[4] = 0;
mylog("%08" PRIX64 " %.4s\n", (uint64_t)mysofa_tell(reader) - 4, buf);
if (mysofa_getc(reader) != 0) {
mylog("object BTHD must have version 0\n");
return MYSOFA_INVALID_FORMAT;
}
btree->type = (uint8_t)mysofa_getc(reader);
btree->node_size = (uint32_t)readValue(reader, 4);
btree->record_size = (uint16_t)readValue(reader, 2);
btree->depth = (uint16_t)readValue(reader, 2);
btree->split_percent = (uint8_t)mysofa_getc(reader);
btree->merge_percent = (uint8_t)mysofa_getc(reader);
btree->root_node_address =
(uint64_t)readValue(reader, reader->superblock.size_of_offsets);
btree->number_of_records = (uint16_t)readValue(reader, 2);
if (btree->number_of_records > 0x1000)
return MYSOFA_UNSUPPORTED_FORMAT;
btree->total_number =
(uint64_t)readValue(reader, reader->superblock.size_of_lengths);
if (btree->total_number > 0x10000000)
return MYSOFA_NO_MEMORY;
btree->records = malloc(sizeof(btree->records[0]) * btree->total_number);
if (!btree->records)
return MYSOFA_NO_MEMORY;
memset(btree->records, 0, sizeof(btree->records[0]) * btree->total_number);
if (mysofa_seek(reader, btree->root_node_address, SEEK_SET) < 0)
return errno;
return readBTLF(reader, btree, btree->number_of_records, btree->records);
}
void btreeFree(struct BTREE *btree) { free(btree->records); }
int treeRead(struct READER *reader, struct DATAOBJECT *data) {
int i, j, err, olen, elements, size, x, y, z, b, e, dy, dz, sx, sy, sz, dzy,
szy;
char *input, *output;
uint8_t node_type, node_level;
uint16_t entries_used;
uint32_t size_of_chunk;
uint32_t filter_mask;
uint64_t address_of_left_sibling, address_of_right_sibling, start[4],
child_pointer, key, store;
char buf[5];
UNUSED(node_level);
UNUSED(address_of_right_sibling);
UNUSED(address_of_left_sibling);
UNUSED(key);
if (data->ds.dimensionality > 3) {
mylog("TREE dimensions > 3"); return MYSOFA_INVALID_FORMAT; }
if (mysofa_read(reader, buf, 4) != 4 || strncmp(buf, "TREE", 4)) {
mylog("cannot read signature of TREE\n"); return MYSOFA_INVALID_FORMAT; }
buf[4] = 0;
mylog("%08" PRIX64 " %.4s\n", (uint64_t)mysofa_tell(reader) - 4, buf);
node_type = (uint8_t)mysofa_getc(reader);
node_level = (uint8_t)mysofa_getc(reader);
entries_used = (uint16_t)readValue(reader, 2);
if (entries_used > 0x1000)
return MYSOFA_UNSUPPORTED_FORMAT; address_of_left_sibling =
readValue(reader, reader->superblock.size_of_offsets);
address_of_right_sibling =
readValue(reader, reader->superblock.size_of_offsets);
elements = 1;
for (j = 0; j < data->ds.dimensionality; j++)
elements *= data->datalayout_chunk[j];
dy = data->datalayout_chunk[1];
dz = data->datalayout_chunk[2];
sx = data->ds.dimension_size[0];
sy = data->ds.dimension_size[1];
sz = data->ds.dimension_size[2];
dzy = dz * dy;
szy = sz * sy;
size = data->datalayout_chunk[data->ds.dimensionality];
mylog("elements %d size %d\n", elements, size);
if (elements <= 0 || size <= 0 || elements >= 0x130000 || size > 0x10)
return MYSOFA_INVALID_FORMAT; if (!(output = malloc(elements * size))) {
return MYSOFA_NO_MEMORY; }
for (e = 0; e < entries_used * 2; e++) {
if (node_type == 0) {
key = readValue(reader, reader->superblock.size_of_lengths);
} else {
size_of_chunk = (uint32_t)readValue(reader, 4);
filter_mask = (uint32_t)readValue(reader, 4);
if (filter_mask) {
mylog("TREE all filters must be enabled\n"); free(output); return MYSOFA_INVALID_FORMAT; }
for (j = 0; j < data->ds.dimensionality; j++) {
start[j] = readValue(reader, 8);
mylog("start %d %" PRIu64 "\n", j, start[j]);
}
if (readValue(reader, 8)) {
break;
}
child_pointer = readValue(reader, reader->superblock.size_of_offsets);
mylog(" data at %" PRIX64 " len %u\n", child_pointer, size_of_chunk);
store = mysofa_tell(reader);
if (mysofa_seek(reader, child_pointer, SEEK_SET) < 0) {
free(output); return errno; }
if (!(input = malloc(size_of_chunk))) {
free(output); return MYSOFA_NO_MEMORY; }
if (mysofa_read(reader, input, size_of_chunk) != size_of_chunk) {
free(output); free(input); return MYSOFA_INVALID_FORMAT; }
olen = elements * size;
err = gunzip(size_of_chunk, input, &olen, output);
free(input);
mylog(" gunzip %d %d %d\n", err, olen, elements * size);
if (err || olen != elements * size) {
free(output); return MYSOFA_INVALID_FORMAT; }
switch (data->ds.dimensionality) {
case 1:
for (i = 0; i < olen; i++) {
b = i / elements;
x = i % elements + start[0];
if (x < sx) {
j = x * size + b;
if (j >= 0 && j < data->data_len) {
((char *)data->data)[j] = output[i];
}
}
}
break;
case 2:
for (i = 0; i < olen; i++) {
b = i / elements;
x = i % elements;
y = x % dy + start[1];
x = x / dy + start[0];
if (y < sy && x < sx) {
j = ((x * sy + y) * size) + b;
if (j >= 0 && j < data->data_len) {
((char *)data->data)[j] = output[i];
}
}
}
break;
case 3:
for (i = 0; i < olen; i++) {
b = i / elements;
x = i % elements;
z = x % dz + start[2];
y = (x / dz) % dy + start[1];
x = (x / dzy) + start[0];
if (z < sz && y < sy && x < sx) {
j = (x * szy + y * sz + z) * size + b;
if (j >= 0 && j < data->data_len) {
((char *)data->data)[j] = output[i];
}
}
}
break;
default:
mylog("invalid dim\n"); return MYSOFA_INTERNAL_ERROR; }
if (mysofa_seek(reader, store, SEEK_SET) < 0) {
free(output); return errno; }
}
}
free(output);
if (mysofa_seek(reader, 4, SEEK_CUR) < 0)
return errno;
return MYSOFA_OK;
}