#include "reader.h"
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int readOCHK(struct READER *reader, struct DATAOBJECT *dataobject,
uint64_t end);
static struct DATAOBJECT *findDataobject(struct READER *reader,
uint64_t address) {
struct DATAOBJECT *p = reader->all;
while (p && p->address != address)
p = p->all;
return p;
}
static int readOHDRHeaderMessageNIL(struct READER *reader, int length) {
if (mysofa_seek(reader, length, SEEK_CUR) < 0)
return errno;
return MYSOFA_OK;
}
static int readOHDRHeaderMessageDataspace1(struct READER *reader,
struct DATASPACE *ds) {
int i;
readValue(reader, 5);
for (i = 0; i < ds->dimensionality; i++) {
if (i < 4) {
ds->dimension_size[i] =
readValue(reader, reader->superblock.size_of_lengths);
if (ds->dimension_size[i] > 1000000) {
mylog("dimension_size is too large\n"); return MYSOFA_INVALID_FORMAT; }
mylog(" dimension %d %" PRIu64 "\n", i, ds->dimension_size[i]);
} else
readValue(reader, reader->superblock.size_of_lengths);
}
if (ds->flags & 1) {
for (i = 0; i < ds->dimensionality; i++) {
if (i < 4)
ds->dimension_max_size[i] =
readValue(reader, reader->superblock.size_of_lengths);
else
readValue(reader, reader->superblock.size_of_lengths);
}
}
if (ds->flags & 2) {
mylog("permutation in OHDR not supported\n"); return MYSOFA_INVALID_FORMAT; }
return MYSOFA_OK;
}
static int readOHDRHeaderMessageDataspace2(struct READER *reader,
struct DATASPACE *ds) {
int i;
ds->type = (uint8_t)mysofa_getc(reader);
for (i = 0; i < ds->dimensionality; i++) {
if (i < 4) {
ds->dimension_size[i] =
readValue(reader, reader->superblock.size_of_lengths);
mylog(" dimension %d %" PRIu64 "\n", i, ds->dimension_size[i]);
} else
readValue(reader, reader->superblock.size_of_lengths);
}
if (ds->flags & 1) {
for (i = 0; i < ds->dimensionality; i++) {
if (i < 4)
ds->dimension_max_size[i] =
readValue(reader, reader->superblock.size_of_lengths);
else
readValue(reader, reader->superblock.size_of_lengths);
}
}
return MYSOFA_OK;
}
static int readOHDRHeaderMessageDataspace(struct READER *reader,
struct DATASPACE *ds) {
int version = mysofa_getc(reader);
ds->dimensionality = (uint8_t)mysofa_getc(reader);
if (ds->dimensionality > 4) {
mylog("dimensionality must be lower than 5\n"); return MYSOFA_INVALID_FORMAT; }
ds->flags = (uint8_t)mysofa_getc(reader);
switch (version) {
case 1:
return readOHDRHeaderMessageDataspace1(reader, ds);
case 2:
return readOHDRHeaderMessageDataspace2(reader, ds);
default:
mylog("object OHDR dataspace message must have version 1 or 2 but is %X at "
"%lX\n",
version, mysofa_tell(reader) - 1);
return MYSOFA_INVALID_FORMAT;
}
}
static int readOHDRHeaderMessageLinkInfo(struct READER *reader,
struct LINKINFO *li) {
if (mysofa_getc(reader) != 0) {
mylog(
"object OHDR link info message must have version 0\n"); return MYSOFA_UNSUPPORTED_FORMAT; }
li->flags = (uint8_t)mysofa_getc(reader);
if (li->flags & 1)
li->maximum_creation_index = readValue(reader, 8);
li->fractal_heap_address =
readValue(reader, reader->superblock.size_of_offsets);
li->address_btree_index =
readValue(reader, reader->superblock.size_of_offsets);
if (li->flags & 2)
li->address_btree_order =
readValue(reader, reader->superblock.size_of_offsets);
return MYSOFA_OK;
}
static int readOHDRHeaderMessageDatatype(struct READER *reader,
struct DATATYPE *dt) {
int i, j, c, err;
char *buffer;
struct DATATYPE dt2;
dt->class_and_version = (uint8_t)mysofa_getc(reader);
if ((dt->class_and_version & 0xf0) != 0x10 &&
(dt->class_and_version & 0xf0) != 0x30) {
mylog("object OHDR datatype message must have version 1 not %d at %lX\n",
dt->class_and_version >> 4, mysofa_tell(reader) - 1);
return MYSOFA_UNSUPPORTED_FORMAT;
}
dt->class_bit_field = (uint32_t)readValue(reader, 3);
dt->size = (uint32_t)readValue(reader, 4);
if (dt->size > 64)
return MYSOFA_UNSUPPORTED_FORMAT;
switch (dt->class_and_version & 0xf) {
case 0:
dt->u.i.bit_offset = readValue(reader, 2);
dt->u.i.bit_precision = readValue(reader, 2);
mylog(" INT bit %d %d %d %d\n", dt->u.i.bit_offset,
dt->u.i.bit_precision, dt->class_and_version >> 4, dt->size);
break;
case 1:
dt->u.f.bit_offset = (uint16_t)readValue(reader, 2);
dt->u.f.bit_precision = (uint16_t)readValue(reader, 2);
dt->u.f.exponent_location = (uint8_t)mysofa_getc(reader);
dt->u.f.exponent_size = (uint8_t)mysofa_getc(reader);
dt->u.f.mantissa_location = (uint8_t)mysofa_getc(reader);
dt->u.f.mantissa_size = (uint8_t)mysofa_getc(reader);
dt->u.f.exponent_bias = (uint32_t)readValue(reader, 4);
mylog(" FLOAT bit %d %d exponent %d %d MANTISSA %d %d OFFSET %d\n",
dt->u.f.bit_offset, dt->u.f.bit_precision, dt->u.f.exponent_location,
dt->u.f.exponent_size, dt->u.f.mantissa_location,
dt->u.f.mantissa_size, dt->u.f.exponent_bias);
if (dt->u.f.bit_offset != 0 || dt->u.f.mantissa_location != 0 ||
(dt->u.f.bit_precision != 32 && dt->u.f.bit_precision != 64) ||
(dt->u.f.bit_precision == 32 &&
(dt->u.f.exponent_location != 23 || dt->u.f.exponent_size != 8 ||
dt->u.f.mantissa_size != 23 || dt->u.f.exponent_bias != 127)) ||
(dt->u.f.bit_precision == 64 &&
(dt->u.f.exponent_location != 52 || dt->u.f.exponent_size != 11 ||
dt->u.f.mantissa_size != 52 || dt->u.f.exponent_bias != 1023)))
return MYSOFA_UNSUPPORTED_FORMAT; break;
case 3:
mylog(" STRING %d %02X\n", dt->size, dt->class_bit_field);
break;
case 6:
mylog(" COMPOUND %d %02X\n", dt->size, dt->class_bit_field);
switch (dt->class_and_version >> 4) {
case 3:
for (i = 0; i < (dt->class_bit_field & 0xffff); i++) {
int maxsize = 0x1000;
buffer = malloc(maxsize);
if (!buffer)
return MYSOFA_NO_MEMORY;
for (j = 0; j < maxsize - 1; j++) {
c = mysofa_getc(reader);
if (c < 0) {
free(buffer);
return MYSOFA_READ_ERROR;
}
buffer[j] = c;
if (c == 0)
break;
}
buffer[j] = 0;
for (j = 0, c = 0; (dt->size >> (8 * j)) > 0; j++) {
c |= mysofa_getc(reader) << (8 * j);
}
mylog(" COMPOUND %s offset %d\n", buffer, c);
free(buffer);
err = readOHDRHeaderMessageDatatype(reader, &dt2);
if (err)
return err; }
break;
case 1:
for (i = 0; i < (dt->class_bit_field & 0xffff); i++) {
char name[256];
int res;
for (j = 0;; j++) {
if (j == sizeof(name))
return MYSOFA_INVALID_FORMAT; res = mysofa_getc(reader);
if (res < 0)
return MYSOFA_READ_ERROR; name[j] = res;
if (name[j] == 0)
break;
}
if (mysofa_seek(reader, (7 - j) & 7, SEEK_CUR))
return MYSOFA_READ_ERROR;
c = readValue(reader, 4);
int dimension = mysofa_getc(reader);
if (dimension != 0) {
mylog("COMPOUND v1 with dimension not supported");
return MYSOFA_INVALID_FORMAT; }
if (mysofa_seek(reader, 3 + 4 + 4 + 4 * 4, SEEK_CUR))
return MYSOFA_READ_ERROR;
mylog(" COMPOUND %s %d %d %lX\n", name, c, dimension,
mysofa_tell(reader));
err = readOHDRHeaderMessageDatatype(reader, &dt2);
if (err)
return err; }
break;
default:
mylog("object OHDR datatype message must have version 1 or 3 not %d\n",
dt->class_and_version >> 4);
return MYSOFA_INVALID_FORMAT;
}
break;
case 7:
mylog(" REFERENCE %d %02X\n", dt->size, dt->class_bit_field);
break;
case 9:
dt->list = dt->size;
mylog(" LIST %d\n", dt->size);
err = readOHDRHeaderMessageDatatype(reader, dt);
if (err)
return err; break;
default:
mylog("object OHDR datatype message has unknown variable type %d\n",
dt->class_and_version & 0xf);
return MYSOFA_UNSUPPORTED_FORMAT;
}
return MYSOFA_OK;
}
static int readOHDRHeaderMessageDataFill1or2(struct READER *reader) {
int spaceAllocationTime = mysofa_getc(reader);
int fillValueWriteTime = mysofa_getc(reader);
int fillValueDefined = mysofa_getc(reader);
if (spaceAllocationTime < 0 || fillValueWriteTime < 0 || fillValueDefined < 0)
return MYSOFA_READ_ERROR;
if ((spaceAllocationTime & ~1) != 2 || fillValueWriteTime != 2 ||
(fillValueDefined & ~1) != 0) {
mylog("spaceAllocationTime %d fillValueWriteTime %d fillValueDefined %d\n",
spaceAllocationTime, fillValueWriteTime, fillValueDefined);
return MYSOFA_INVALID_FORMAT; }
if (fillValueDefined > 0) {
uint32_t size = (uint32_t)readValue(reader, 4);
if (mysofa_seek(reader, size, SEEK_CUR) < 0)
return errno; }
return MYSOFA_OK;
}
static int readOHDRHeaderMessageDataFill3(struct READER *reader) {
uint8_t flags;
uint32_t size;
flags = (uint8_t)mysofa_getc(reader);
if (flags & (1 << 5)) {
size = (uint32_t)readValue(reader, 4);
if (mysofa_seek(reader, size, SEEK_CUR) < 0)
return errno; }
return MYSOFA_OK;
}
static int readOHDRHeaderMessageDataFill(struct READER *reader) {
int version = mysofa_getc(reader);
switch (version) {
case 1:
case 2:
return readOHDRHeaderMessageDataFill1or2(reader);
case 3:
return readOHDRHeaderMessageDataFill3(reader);
default:
mylog("object OHDR data storage fill value message must have version 1,2, "
"or 3 not "
"%d\n",
version);
return MYSOFA_INVALID_FORMAT;
}
}
static int readOHDRHeaderMessageDataFillOld(struct READER *reader) {
uint32_t size;
size = (uint32_t)readValue(reader, 4);
if (mysofa_seek(reader, size, SEEK_CUR) < 0)
return errno;
return MYSOFA_OK;
}
static int readOHDRHeaderMessageDataLayout(struct READER *reader,
struct DATAOBJECT *data) {
int i, err;
unsigned size;
uint8_t dimensionality, layout_class;
uint32_t dataset_element_size;
uint64_t data_address, store, data_size;
UNUSED(dataset_element_size);
UNUSED(data_size);
if (mysofa_getc(reader) != 3) {
mylog("object OHDR message data layout message must have version 3\n");
return MYSOFA_INVALID_FORMAT;
}
layout_class = (uint8_t)mysofa_getc(reader);
mylog("data layout %d\n", layout_class);
switch (layout_class) {
#if 0#endif
case 1:
data_address = readValue(reader, reader->superblock.size_of_offsets);
data_size = readValue(reader, reader->superblock.size_of_lengths);
mylog("CHUNK Contiguous SIZE %" PRIu64 "\n", data_size);
if (validAddress(reader, data_address)) {
store = mysofa_tell(reader);
if (mysofa_seek(reader, data_address, SEEK_SET) < 0)
return errno; if (data->data) {
free(data->data);
data->data = NULL;
}
if (data_size > 0x10000000)
return MYSOFA_INVALID_FORMAT;
data->data_len = data_size;
data->data = calloc(1, data_size);
if (!data->data)
return MYSOFA_NO_MEMORY;
err = mysofa_read(reader, data->data, data_size);
if (err != data_size)
return MYSOFA_READ_ERROR; if (mysofa_seek(reader, store, SEEK_SET) < 0)
return errno; }
break;
case 2:
dimensionality = (uint8_t)mysofa_getc(reader);
mylog("dimensionality %d\n", dimensionality);
if (dimensionality < 1 || dimensionality > DATAOBJECT_MAX_DIMENSIONALITY) {
mylog("data layout 2: invalid dimensionality %d %lu %lu\n",
dimensionality, sizeof(data->datalayout_chunk),
sizeof(data->datalayout_chunk[0]));
return MYSOFA_INVALID_FORMAT; }
data_address = readValue(reader, reader->superblock.size_of_offsets);
mylog(" CHUNK %" PRIX64 "\n", data_address);
for (i = 0; i < dimensionality; i++) {
data->datalayout_chunk[i] = readValue(reader, 4);
mylog(" %d\n", data->datalayout_chunk[i]);
}
size = data->datalayout_chunk[dimensionality - 1];
for (i = 0; i < data->ds.dimensionality; i++)
size *= data->ds.dimension_size[i];
if (validAddress(reader, data_address) && dimensionality <= 4) {
store = mysofa_tell(reader);
if (mysofa_seek(reader, data_address, SEEK_SET) < 0)
return errno; if (!data->data) {
if (size > 0x10000000)
return MYSOFA_INVALID_FORMAT; data->data_len = size;
data->data = calloc(1, size);
if (!data->data)
return MYSOFA_NO_MEMORY; }
err = treeRead(reader, data);
if (err)
return err; if (mysofa_seek(reader, store, SEEK_SET) < 0)
return errno; }
break;
default:
mylog("object OHDR message data layout message has unknown layout class "
"%d\n",
layout_class);
return MYSOFA_INVALID_FORMAT;
}
return MYSOFA_OK;
}
static int readOHDRHeaderMessageGroupInfo(struct READER *reader,
struct GROUPINFO *gi) {
if (mysofa_getc(reader) != 0) {
mylog("object OHDR group info message must have version 0\n");
return MYSOFA_UNSUPPORTED_FORMAT;
}
gi->flags = (uint8_t)mysofa_getc(reader);
if (gi->flags & 1) {
gi->maximum_compact_value = (uint16_t)readValue(reader, 2);
gi->minimum_dense_value = (uint16_t)readValue(reader, 2);
}
if (gi->flags & 2) {
gi->number_of_entries = (uint16_t)readValue(reader, 2);
gi->length_of_entries = (uint16_t)readValue(reader, 2);
}
return MYSOFA_OK;
}
static int readOHDRHeaderMessageFilterPipelineV1(struct READER *reader,
uint8_t filters) {
int i, j;
uint16_t filter_identification_value, flags, number_client_data_values,
namelength;
if (readValue(reader, 6) != 0) {
mylog("reserved values not zero\n");
return MYSOFA_INVALID_FORMAT;
}
for (i = 0; i < filters; i++) {
filter_identification_value = (uint16_t)readValue(reader, 2);
switch (filter_identification_value) {
case 1:
case 2:
break;
default:
mylog("object OHDR filter pipeline message contains unsupported filter: "
"%d %lX\n",
filter_identification_value, mysofa_tell(reader) - 2);
return MYSOFA_INVALID_FORMAT;
}
namelength = (uint16_t)readValue(reader, 2);
flags = (uint16_t)readValue(reader, 2);
number_client_data_values = (uint16_t)readValue(reader, 2);
if (namelength > 0)
if (mysofa_seek(reader, ((namelength - 1) & ~7) + 8, SEEK_CUR) ==
-1) return MYSOFA_READ_ERROR;
mylog(" filter %d namelen %d flags %04X values %d\n",
filter_identification_value, namelength, flags,
number_client_data_values);
if (number_client_data_values > 0x1000)
return MYSOFA_UNSUPPORTED_FORMAT;
for (j = 0; j < number_client_data_values; j++) {
readValue(reader, 4);
}
if ((number_client_data_values & 1) == 1)
readValue(reader, 4);
}
return MYSOFA_OK;
}
static int readOHDRHeaderMessageFilterPipelineV2(struct READER *reader,
uint8_t filters) {
int i, j;
uint16_t filter_identification_value, flags, number_client_data_values;
uint32_t client_data;
uint64_t maximum_compact_value, minimum_dense_value, number_of_entries,
length_of_entries;
UNUSED(flags);
UNUSED(client_data);
UNUSED(maximum_compact_value);
UNUSED(minimum_dense_value);
UNUSED(number_of_entries);
UNUSED(length_of_entries);
for (i = 0; i < filters; i++) {
filter_identification_value = (uint16_t)readValue(reader, 2);
switch (filter_identification_value) {
case 1:
case 2:
break;
default:
mylog("object OHDR filter pipeline message contains unsupported filter: "
"%d\n",
filter_identification_value);
return MYSOFA_INVALID_FORMAT;
}
mylog(" filter %d\n", filter_identification_value);
flags = (uint16_t)readValue(reader, 2);
number_client_data_values = (uint16_t)readValue(reader, 2);
if (number_client_data_values > 0x1000)
return MYSOFA_UNSUPPORTED_FORMAT;
for (j = 0; j < number_client_data_values; j++) {
client_data = readValue(reader, 4);
}
}
return MYSOFA_OK;
}
static int readOHDRHeaderMessageFilterPipeline(struct READER *reader) {
int filterversion, filters;
filterversion = mysofa_getc(reader);
filters = mysofa_getc(reader);
if (filterversion < 0 || filters < 0)
return MYSOFA_READ_ERROR;
if (filters > 32) {
mylog("object OHDR filter pipeline message has too many filters: %d\n",
filters);
return MYSOFA_INVALID_FORMAT;
}
switch (filterversion) {
case 1:
return readOHDRHeaderMessageFilterPipelineV1(reader, filters);
case 2:
return readOHDRHeaderMessageFilterPipelineV2(reader, filters);
default:
mylog(
"object OHDR filter pipeline message must have version 1 or 2 not %d\n",
filterversion);
return MYSOFA_INVALID_FORMAT;
}
}
int readDataVar(struct READER *reader, struct DATAOBJECT *data,
struct DATATYPE *dt, struct DATASPACE *ds) {
char *buffer, number[20];
uint64_t reference, gcol = 0, dataobject;
int err;
struct DATAOBJECT *referenceData;
if (dt->list) {
if (dt->list - dt->size == 8) {
readValue(reader, 4);
gcol = readValue(reader, 4);
} else {
gcol = readValue(reader, dt->list - dt->size);
}
mylog(" GCOL %d %8" PRIX64 " %8lX\n", dt->list - dt->size, gcol,
mysofa_tell(reader));
}
switch (dt->class_and_version & 0xf) {
case 0:
mylog("FIXED POINT todo %lX %d\n", mysofa_tell(reader), dt->size);
if (mysofa_seek(reader, dt->size, SEEK_CUR))
return errno; break;
case 3:
buffer = malloc(dt->size + 1);
if (buffer == NULL) {
return MYSOFA_NO_MEMORY; }
if (mysofa_read(reader, buffer, dt->size) != dt->size) {
free(buffer); return MYSOFA_READ_ERROR; }
buffer[dt->size] = 0;
mylog("STRING %s\n", buffer);
data->string = buffer;
break;
case 6:
mylog("COMPONENT todo %lX %d\n", mysofa_tell(reader), dt->size);
if (mysofa_seek(reader, dt->size, SEEK_CUR))
return errno; break;
case 7:
readValue(reader, 4);
reference = readValue(reader, dt->size - 4);
mylog(" REFERENCE size %d %" PRIX64 "\n", dt->size, reference);
if (!!(err = gcolRead(reader, gcol, reference, &dataobject))) {
return MYSOFA_OK;
}
referenceData = findDataobject(reader, dataobject);
if (referenceData)
buffer = referenceData->name;
else {
sprintf(number, "REF%08lX", (long unsigned int)reference);
buffer = number;
}
mylog(" REFERENCE %" PRIX64 " %" PRIX64 " %s\n", reference, dataobject,
buffer);
if (data->string) {
data->string =
realloc(data->string, strlen(data->string) + strlen(buffer) + 2);
if (!data->string)
return MYSOFA_NO_MEMORY;
strcat(data->string, ",");
strcat(data->string, buffer);
} else {
data->string = mysofa_strdup(buffer);
}
break;
default:
mylog("data reader unknown type %d\n", dt->class_and_version & 0xf);
return MYSOFA_INTERNAL_ERROR;
}
return MYSOFA_OK;
}
int readDataDim(struct READER *reader, struct DATAOBJECT *da,
struct DATATYPE *dt, struct DATASPACE *ds, int dim) {
int i, err;
if (dim >= sizeof(ds->dimension_size) / sizeof(ds->dimension_size[0]))
return MYSOFA_UNSUPPORTED_FORMAT;
for (i = 0; i < ds->dimension_size[dim]; i++) {
if (dim + 1 < ds->dimensionality) {
if (!!(err = readDataDim(reader, da, dt, ds, dim + 1))) {
return err; }
} else {
if (!!(err = readDataVar(reader, da, dt, ds))) {
return err; }
}
}
return MYSOFA_OK;
}
int readData(struct READER *reader, struct DATAOBJECT *da, struct DATATYPE *dt,
struct DATASPACE *ds) {
if (ds->dimensionality == 0) {
ds->dimension_size[0] = 1;
}
return readDataDim(reader, da, dt, ds, 0);
}
static int readOHDRHeaderMessageContinue(struct READER *reader,
struct DATAOBJECT *dataobject) {
int err;
uint64_t offset, length;
long store;
offset = readValue(reader, reader->superblock.size_of_offsets);
length = readValue(reader, reader->superblock.size_of_lengths);
if (offset > 0x2000000 || length > 0x10000000)
return MYSOFA_UNSUPPORTED_FORMAT;
mylog(" continue %08" PRIX64 " %08" PRIX64 "\n", offset, length);
if (reader->recursive_counter >= 25) {
mylog("recursive problem");
return MYSOFA_UNSUPPORTED_FORMAT; } else
reader->recursive_counter++;
store = mysofa_tell(reader);
if (mysofa_seek(reader, offset, SEEK_SET) < 0)
return errno;
err = readOCHK(reader, dataobject, offset + length);
if (err)
return err;
if (store < 0)
return MYSOFA_READ_ERROR; if (mysofa_seek(reader, store, SEEK_SET) < 0)
return errno;
mylog(" continue back\n");
return MYSOFA_OK;
}
static int readOHDRHeaderMessageAttribute(struct READER *reader,
struct DATAOBJECT *dataobject) {
int err;
uint8_t flags, encoding;
uint16_t name_size, datatype_size, dataspace_size;
char *name;
struct DATAOBJECT d;
struct MYSOFA_ATTRIBUTE *attr;
UNUSED(encoding);
UNUSED(datatype_size);
UNUSED(dataspace_size);
memset(&d, 0, sizeof(d));
int version = mysofa_getc(reader);
if (version != 1 && version != 3) {
mylog("object OHDR attribute message must have version 1 or 3\n");
return MYSOFA_INVALID_FORMAT;
}
flags = (uint8_t)mysofa_getc(reader);
name_size = (uint16_t)readValue(reader, 2);
datatype_size = (uint16_t)readValue(reader, 2);
dataspace_size = (uint16_t)readValue(reader, 2);
if (version == 3)
encoding = (uint8_t)mysofa_getc(reader);
if (name_size > 0x1000)
return MYSOFA_NO_MEMORY; name = malloc(name_size + 1);
if (!name)
return MYSOFA_NO_MEMORY; if (mysofa_read(reader, name, name_size) != name_size) {
free(name); return errno; }
if (version == 1 && mysofa_seek(reader, (8 - name_size) & 7, SEEK_CUR) != 0) {
free(name); return errno; }
name[name_size] = 0;
mylog(" attribute name %s %d %d %lX\n", name, datatype_size, dataspace_size,
mysofa_tell(reader));
if (version == 3 && (flags & 3)) {
mylog("object OHDR attribute message must not have any flags set\n");
free(name);
return MYSOFA_INVALID_FORMAT;
}
err = readOHDRHeaderMessageDatatype(reader, &d.dt);
if (err) {
mylog("object OHDR attribute message read datatype error\n");
free(name);
return MYSOFA_INVALID_FORMAT;
}
if (version == 1) {
if (mysofa_seek(reader, (8 - datatype_size) & 7, SEEK_CUR) < 0) {
free(name);
return errno;
}
}
err = readOHDRHeaderMessageDataspace(reader, &d.ds);
if (err) {
mylog("object OHDR attribute message read dataspace error\n");
free(name);
return MYSOFA_INVALID_FORMAT;
}
if (version == 1) {
if (mysofa_seek(reader, (8 - dataspace_size) & 7, SEEK_CUR) < 0) {
free(name);
return errno;
}
}
err = readData(reader, &d, &d.dt, &d.ds);
if (err) {
mylog("object OHDR attribute message read data error\n");
free(name);
return MYSOFA_INVALID_FORMAT;
}
attr = malloc(sizeof(struct MYSOFA_ATTRIBUTE));
if (!attr) {
free(name);
return MYSOFA_NO_MEMORY;
}
attr->name = name;
attr->value = d.string;
d.string = NULL;
attr->next = dataobject->attributes;
dataobject->attributes = attr;
dataobjectFree(reader, &d);
return MYSOFA_OK;
}
static int readOHDRHeaderMessageAttributeInfo(struct READER *reader,
struct ATTRIBUTEINFO *ai) {
if (mysofa_getc(reader) != 0) {
mylog("object OHDR attribute info message must have version 0\n");
return MYSOFA_UNSUPPORTED_FORMAT;
}
ai->flags = (uint8_t)mysofa_getc(reader);
if (ai->flags & 1)
ai->maximum_creation_index = readValue(reader, 2);
ai->fractal_heap_address =
readValue(reader, reader->superblock.size_of_offsets);
ai->attribute_name_btree =
readValue(reader, reader->superblock.size_of_offsets);
if (ai->flags & 2)
ai->attribute_creation_order_btree =
readValue(reader, reader->superblock.size_of_offsets);
return MYSOFA_OK;
}
static int readOHDRmessages(struct READER *reader,
struct DATAOBJECT *dataobject,
uint64_t end_of_messages) {
int err;
long end;
while (mysofa_tell(reader) <
end_of_messages - 4) {
uint8_t header_message_type = (uint8_t)mysofa_getc(reader);
uint16_t header_message_size = (uint16_t)readValue(reader, 2);
uint8_t header_message_flags = (uint8_t)mysofa_getc(reader);
if ((header_message_flags & ~5) != 0) {
mylog("OHDR unsupported OHDR message flag %02X\n", header_message_flags);
return MYSOFA_UNSUPPORTED_FORMAT;
}
if ((dataobject->flags & (1 << 2)) != 0)
if (mysofa_seek(reader, 2, SEEK_CUR) < 0)
return errno;
mylog(" OHDR message type %2d offset %6lX len %4X\n", header_message_type,
mysofa_tell(reader), header_message_size);
end = mysofa_tell(reader) + header_message_size;
switch (header_message_type) {
case 0:
if (!!(err = readOHDRHeaderMessageNIL(reader, header_message_size)))
return err;
break;
case 1:
if (!!(err = readOHDRHeaderMessageDataspace(reader, &dataobject->ds)))
return err;
break;
case 2:
if (!!(err = readOHDRHeaderMessageLinkInfo(reader, &dataobject->li)))
return err;
break;
case 3:
if (!!(err = readOHDRHeaderMessageDatatype(reader, &dataobject->dt)))
return err;
break;
case 4:
if (!!(err = readOHDRHeaderMessageDataFillOld(reader)))
return err;
break;
case 5:
if (!!(err = readOHDRHeaderMessageDataFill(reader)))
return err;
break;
case 8:
if (!!(err = readOHDRHeaderMessageDataLayout(reader, dataobject)))
return err;
break;
case 10:
if (!!(err = readOHDRHeaderMessageGroupInfo(reader, &dataobject->gi)))
return err;
break;
case 11:
if (!!(err = readOHDRHeaderMessageFilterPipeline(reader)))
return err;
break;
case 12:
if (!!(err = readOHDRHeaderMessageAttribute(reader, dataobject)))
return err;
break;
case 16:
if (!!(err = readOHDRHeaderMessageContinue(reader, dataobject)))
return err;
break;
case 21:
if (!!(err = readOHDRHeaderMessageAttributeInfo(reader, &dataobject->ai)))
return err;
break;
default:
mylog("OHDR unknown header message of type %d\n", header_message_type);
return MYSOFA_UNSUPPORTED_FORMAT;
}
if (mysofa_tell(reader) != end) {
mylog("OHDR message length mismatch by %ld\n", mysofa_tell(reader) - end);
return MYSOFA_INTERNAL_ERROR;
}
}
if (mysofa_seek(reader, end_of_messages + 4, SEEK_SET) <
0)
return errno;
return MYSOFA_OK;
}
static int readOCHK(struct READER *reader, struct DATAOBJECT *dataobject,
uint64_t end) {
int err;
char buf[5];
if (mysofa_read(reader, buf, 4) != 4 || strncmp(buf, "OCHK", 4)) {
mylog("cannot read signature of OCHK\n");
return MYSOFA_INVALID_FORMAT;
}
buf[4] = 0;
mylog("%08" PRIX64 " %.4s\n", (uint64_t)mysofa_tell(reader) - 4, buf);
err = readOHDRmessages(reader, dataobject, end - 4);
if (err) {
return err;
}
return MYSOFA_OK;
}
int dataobjectRead(struct READER *reader, struct DATAOBJECT *dataobject,
char *name) {
uint64_t size_of_chunk, end_of_messages;
int err;
char buf[5];
memset(dataobject, 0, sizeof(*dataobject));
dataobject->address = mysofa_tell(reader);
dataobject->name = name;
if (mysofa_read(reader, buf, 4) != 4 || strncmp(buf, "OHDR", 4)) {
mylog("cannot read signature of data object\n");
return MYSOFA_INVALID_FORMAT;
}
buf[4] = 0;
mylog("%08" PRIX64 " %.4s\n", dataobject->address, buf);
if (mysofa_getc(reader) != 2) {
mylog("object OHDR must have version 2\n");
return MYSOFA_UNSUPPORTED_FORMAT;
}
dataobject->flags = (uint8_t)mysofa_getc(reader);
if (dataobject->flags & (1 << 5)) {
if (mysofa_seek(reader, 16, SEEK_CUR) < 0)
return errno;
}
if (dataobject->flags & (1 << 4)) {
mylog("OHDR: unsupported flags bit 4: %02X\n", dataobject->flags);
return MYSOFA_UNSUPPORTED_FORMAT;
}
size_of_chunk = readValue(reader, 1 << (dataobject->flags & 3));
if (size_of_chunk > 0x1000000)
return MYSOFA_UNSUPPORTED_FORMAT;
end_of_messages = mysofa_tell(reader) + size_of_chunk;
err = readOHDRmessages(reader, dataobject, end_of_messages);
if (err) {
return err;
}
if (validAddress(reader, dataobject->ai.attribute_name_btree)) {
}
if (validAddress(reader, dataobject->ai.fractal_heap_address)) {
if (mysofa_seek(reader, dataobject->ai.fractal_heap_address, SEEK_SET) < 0)
return errno;
err = fractalheapRead(reader, dataobject, &dataobject->attributes_heap);
if (err)
return err;
}
if (validAddress(reader, dataobject->li.fractal_heap_address)) {
mysofa_seek(reader, dataobject->li.fractal_heap_address, SEEK_SET);
err = fractalheapRead(reader, dataobject, &dataobject->objects_heap);
if (err)
return err;
}
if (validAddress(reader, dataobject->li.address_btree_index)) {
}
dataobject->all = reader->all;
reader->all = dataobject;
return MYSOFA_OK;
}
void dataobjectFree(struct READER *reader, struct DATAOBJECT *dataobject) {
struct DATAOBJECT **p;
btreeFree(&dataobject->attributes_btree);
fractalheapFree(&dataobject->attributes_heap);
btreeFree(&dataobject->objects_btree);
fractalheapFree(&dataobject->objects_heap);
while (dataobject->attributes) {
struct MYSOFA_ATTRIBUTE *attr = dataobject->attributes;
dataobject->attributes = attr->next;
free(attr->name);
free(attr->value);
free(attr);
}
while (dataobject->directory) {
struct DIR *dir = dataobject->directory;
dataobject->directory = dir->next;
dataobjectFree(reader, &dir->dataobject);
free(dir);
}
free(dataobject->data);
free(dataobject->string);
free(dataobject->name);
p = &reader->all;
while (*p) {
if ((*p) == dataobject) {
*p = dataobject->all;
break;
}
p = &((*p)->all);
}
}