#include "reader.h"
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int superblockRead2or3(struct READER *reader, struct SUPERBLOCK *superblock) {
superblock->size_of_offsets = (uint8_t)mysofa_getc(reader);
superblock->size_of_lengths = (uint8_t)mysofa_getc(reader);
if (mysofa_getc(reader) < 0)
return MYSOFA_READ_ERROR;
if (superblock->size_of_offsets < 2 || superblock->size_of_offsets > 8 ||
superblock->size_of_lengths < 2 || superblock->size_of_lengths > 8) {
mylog("size of offsets and length is invalid: %d %d\n",
superblock->size_of_offsets, superblock->size_of_lengths);
return MYSOFA_UNSUPPORTED_FORMAT;
}
superblock->base_address = readValue(reader, superblock->size_of_offsets);
superblock->superblock_extension_address =
readValue(reader, superblock->size_of_offsets);
superblock->end_of_file_address =
readValue(reader, superblock->size_of_offsets);
superblock->root_group_object_header_address =
readValue(reader, superblock->size_of_offsets);
if (superblock->base_address != 0) {
mylog("base address is not null\n");
return MYSOFA_UNSUPPORTED_FORMAT;
}
if (mysofa_seek(reader, 0L, SEEK_END))
return errno;
if (superblock->end_of_file_address != mysofa_tell(reader)) {
mylog("file size mismatch\n");
return MYSOFA_INVALID_FORMAT;
}
if (mysofa_seek(reader, superblock->root_group_object_header_address,
SEEK_SET)) {
mylog("cannot seek to first object at %" PRId64 "\n",
superblock->root_group_object_header_address);
return errno;
}
return dataobjectRead(reader, &superblock->dataobject, NULL);
}
int superblockRead0or1(struct READER *reader, struct SUPERBLOCK *superblock,
int version) {
if (mysofa_getc(reader) !=
0)
return MYSOFA_INVALID_FORMAT;
if (mysofa_getc(reader) !=
0)
return MYSOFA_INVALID_FORMAT;
if (mysofa_getc(reader) != 0)
return MYSOFA_INVALID_FORMAT;
if (mysofa_getc(reader) !=
0)
return MYSOFA_INVALID_FORMAT;
superblock->size_of_offsets = (uint8_t)mysofa_getc(reader);
superblock->size_of_lengths = (uint8_t)mysofa_getc(reader);
if (mysofa_getc(reader) != 0)
return MYSOFA_INVALID_FORMAT;
if (superblock->size_of_offsets < 2 || superblock->size_of_offsets > 8 ||
superblock->size_of_lengths < 2 || superblock->size_of_lengths > 8) {
mylog("size of offsets and length is invalid: %d %d\n",
superblock->size_of_offsets, superblock->size_of_lengths);
return MYSOFA_UNSUPPORTED_FORMAT;
}
readValue(reader, 2);
readValue(reader, 2);
if (readValue(reader, 4) != 0) { mylog("File Consistency Flags are not zero\n");
return MYSOFA_UNSUPPORTED_FORMAT;
}
if (version == 1) {
readValue(reader, 2);
readValue(reader, 2);
}
superblock->base_address = readValue(reader, superblock->size_of_offsets);
if (superblock->base_address != 0) {
mylog("base address is not null\n");
return MYSOFA_UNSUPPORTED_FORMAT;
}
readValue(reader,
superblock->size_of_offsets);
superblock->end_of_file_address =
readValue(reader, superblock->size_of_offsets);
readValue(reader,
superblock->size_of_offsets);
readValue(reader, superblock->size_of_offsets);
superblock->root_group_object_header_address = readValue(
reader, superblock->size_of_offsets);
uint64_t cache_type = readValue(reader, 4);
switch (cache_type) {
case 0:
case 1:
case 2:
break;
default:
mylog("cache type must be 0,1, or 2 not %" PRIu64 "\n", cache_type);
return MYSOFA_UNSUPPORTED_FORMAT;
}
if (mysofa_seek(reader, 0L, SEEK_END))
return errno;
if (superblock->end_of_file_address != mysofa_tell(reader)) {
mylog("file size mismatch\n");
}
if (mysofa_seek(reader, superblock->root_group_object_header_address,
SEEK_SET)) {
mylog("cannot seek to first object at %" PRId64 "\n",
superblock->root_group_object_header_address);
return errno;
}
return dataobjectRead(reader, &superblock->dataobject, NULL);
}
int superblockRead(struct READER *reader, struct SUPERBLOCK *superblock) {
char buf[8];
memset(superblock, 0, sizeof(*superblock));
if (mysofa_read(reader, buf, 8) != 8 ||
strncmp("\211HDF\r\n\032\n", buf, 8)) {
mylog("file does not have correct signature");
return MYSOFA_INVALID_FORMAT;
}
int version = mysofa_getc(reader);
switch (version) {
case 0:
case 1:
return superblockRead0or1(reader, superblock, version);
case 2:
case 3:
return superblockRead2or3(reader, superblock);
default:
mylog("superblock must have version 0, 1, 2, or 3 but has %d\n", version);
return MYSOFA_INVALID_FORMAT;
}
}
void superblockFree(struct READER *reader, struct SUPERBLOCK *superblock) {
dataobjectFree(reader, &superblock->dataobject);
}