summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2019-07-14 15:42:30 +0200
committerPaweł Redman <pawel.redman@gmail.com>2019-07-14 15:42:30 +0200
commite7d138caba5178118c6466584b77d791318d9082 (patch)
tree63ebc4ffef4d712df7ff8ae6a67ec37313453167
parentdcf3c8f677ed0d864604ba0a43d3b971510962e6 (diff)
Refactor the data structure
Move away from ad-hoc prints to being able to store the entire file structure in memory for later processing or storing.
-rw-r--r--src/e2e.c376
-rw-r--r--src/e2e.h63
-rw-r--r--src/main.c14
3 files changed, 247 insertions, 206 deletions
diff --git a/src/e2e.c b/src/e2e.c
index 1ab1449..cb5dc62 100644
--- a/src/e2e.c
+++ b/src/e2e.c
@@ -1,9 +1,21 @@
+#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#include <math.h>
#include "e2e.h"
-uint32_t u32le(const char *src)
+static uint16_t u16le(const char *src)
+{
+ uint8_t bytes[2];
+
+ memcpy(bytes, src, 2);
+
+ return (uint16_t)bytes[0]
+ + (((uint16_t)bytes[1]) << 8);
+}
+
+static uint32_t u32le(const char *src)
{
uint8_t bytes[4];
@@ -15,20 +27,20 @@ uint32_t u32le(const char *src)
+ (((uint32_t)bytes[3]) << 24);
}
-static int make_pointer(const char *start, const char *end,
- const char *pos, const char **out)
+static int make_pointer(const struct e2e_data *data, const char *pos,
+ const char **out)
{
- uint32_t ptroffs;
+ uint32_t offs;
- ptroffs = u32le(pos);
+ offs = u32le(pos);
- if (!ptroffs)
+ if (!offs)
*out = NULL;
else {
- if (ptroffs > end - start)
+ if (offs > data->end - data->start)
return 1;
- *out = start + ptroffs;
+ *out = data->start + offs;
}
return 0;
@@ -61,166 +73,135 @@ static int make_pointer(const char *start, const char *end,
#define CHUNK_TYPE 52
#define CHUNK_HEADER_END 60
-#define DATA_IMAGE 0x40000000
-
#define IMAGE_SIZE 0
#define IMAGE_TYPE 4
#define IMAGE_WIDTH 12
#define IMAGE_HEIGHT 16
#define IMAGE_IMAGE 20
-#define IMAGE_FUNDUS 0x02010201
-#define IMAGE_TOMOGRAM 0x02200201
-
#define UF16_MANTISSA_MASK ((1 << 11) - 1) // 10 most significant bits
+#define UF16_EXP_OFFSET -38 // FIXME: pure guess
-struct e2e_directory {
- size_t num_entries;
- const char *current, *next;
-};
-
-struct e2e_entry {
- const char *start;
- size_t size;
-
- uint32_t patient_id, study_id, series_id, slice_id, type;
-};
-
-struct e2e_chunk {
- const char *origin;
- const struct e2e_entry *entry;
-
- size_t size;
- uint32_t patient_id, study_id, series_id, slice_id, type;
-};
-
-struct e2e_fundus {
- size_t size, width, height;
-
- uint32_t type;
-
-};
-
-static int read_fundus(const char *start, const char *end, const char *cursor,
- size_t width, size_t height)
+static int read_fundus(struct e2e_data *data, const char *cursor,
+ struct e2e_image *image)
{
- FILE *fp;
- char buffer[1024];
+ // This cast is _technically_ illegal, but I can't think of a way in
+ // which this would cause problems in practice.
+ image->fundus = (const uint8_t*)cursor;
- snprintf(buffer, sizeof(buffer), "out/fundus_%tx.py", cursor - start);
- fp = fopen(buffer, "w");
-
- fprintf(fp, "data = [\n");
- for (size_t y = 0; y < height; y++) {
- fprintf(fp, "\t[");
-
- for (size_t x = 0; x < width; x++) {
- uint8_t px;
+ return 0;
+}
- memcpy(&px, cursor + y * width + x, 1);
- fprintf(fp, "%s% 3hhu", x ? ", " : "", px);
- }
- fprintf(fp, "]%s\n", y + 1 >= height ? "" : ",");
+static int read_tomogram(struct e2e_data *data, const char *cursor,
+ struct e2e_image *image)
+{
+ image->tomogram = calloc(image->width * image->height, sizeof(float));
+ if (!image->tomogram)
+ return ENOMEM;
+
+ for (size_t y = 0; y < image->height; y++)
+ for (size_t x = 0; x < image->width; x++) {
+ size_t i = y * image->width + x;
+ uint16_t raw;
+ int exp, man;
+
+ raw = u16le(cursor + i * 2);
+ man = raw & UF16_MANTISSA_MASK;
+ exp = (raw & ~UF16_MANTISSA_MASK) >> 10;
+ image->tomogram[i] = ldexpf(man, exp2f(exp + UF16_EXP_OFFSET));
}
- fprintf(fp, "]\n");
- fclose(fp);
return 0;
}
-static int read_tomogram(const char *start, const char *end, const char *cursor,
- size_t width, size_t height)
+static int read_image(struct e2e_data *data, const char *cursor,
+ struct e2e_image *image)
{
- FILE *fp;
- char buffer[1024];
-
- snprintf(buffer, sizeof(buffer), "out/tomogram_%tx.py", cursor - start);
- fp = fopen(buffer, "w");
-
- fprintf(fp, "data = [\n");
- for (size_t y = 0; y < height; y++) {
- fprintf(fp, "\t[");
-
- for (size_t x = 0; x < width; x++) {
- uint16_t raw;
- int exp, man;
- float px;
+ if (cursor + IMAGE_IMAGE > data->end) {
+ fprintf(stderr, "Image data at %td ends past the end of file.\n",
+ cursor - data->start);
+ return 1;
+ }
- memcpy(&raw, cursor + (y * width + x) * 2, 2);
+ image->size = u32le(cursor + IMAGE_SIZE);
+ image->type = u32le(cursor + IMAGE_TYPE);
+ image->width = u32le(cursor + IMAGE_WIDTH);
+ image->height = u32le(cursor + IMAGE_HEIGHT);
+ cursor += IMAGE_IMAGE;
- man = raw & UF16_MANTISSA_MASK;
- exp = (raw & ~UF16_MANTISSA_MASK) >> 10;
+ switch (image->type) {
+ case IMAGE_FUNDUS:
+ return read_fundus(data, cursor, image);
- px = man * exp2f(exp);
- fprintf(fp, "%s%e", x ? ", " : "", px);
- }
- fprintf(fp, "]%s\n", y + 1 >= height ? "" : ",");
+ case IMAGE_TOMOGRAM:
+ return read_tomogram(data, cursor, image);
}
- fprintf(fp, "]\n");
- fclose(fp);
return 0;
}
-static int read_image(const char *start, const char *end,
- const struct e2e_chunk *chunk)
+static int read_entry(struct e2e_data *data, const char *cursor,
+ struct e2e_entry *entry)
{
- const char *cursor = chunk->origin + CHUNK_HEADER_END;
- size_t size, width, height;
- uint32_t type;
+ const char *pos;
+ struct e2e_chunk *chunk;
- if (cursor + IMAGE_IMAGE > end) {
- fprintf(stderr, "Image data at %td ends past the end of file.\n",
- cursor - start);
+ if (cursor + ENTRY_END > data->end) {
+ fprintf(stderr, "Entry at %td data->ends past the data->end of file.\n",
+ cursor - data->start);
return 1;
}
- size = u32le(cursor + IMAGE_SIZE);
- type = u32le(cursor + IMAGE_TYPE);
- width = u32le(cursor + IMAGE_WIDTH);
- height = u32le(cursor + IMAGE_HEIGHT);
-
- printf("# %08tx Image data: %zux%zu, size=%zu\n",
- cursor - start, width, height, size);
- printf("# Slice is %d\n", chunk->slice_id);
- printf("# Type is %08x\n", type);
+ if (make_pointer(data, cursor + ENTRY_POS, &pos)) {
+ fprintf(stderr, "Entry at %td has a bad 'pos' entry.\n",
+ cursor - data->start);
+ return 1;
+ }
- switch (type) {
- case IMAGE_FUNDUS:
- read_fundus(start, end, cursor + IMAGE_IMAGE, width, height);
- break;
+ if (pos != cursor) {
+ fprintf(stderr, "Entry at %td has a 'pos' entry that differs from the entry's actual position",
+ cursor - data->start);
+ return 1;
+ }
- case IMAGE_TOMOGRAM:
- read_tomogram(start, end, cursor + IMAGE_IMAGE, width, height);
- break;
+ if (make_pointer(data, cursor + ENTRY_START, &entry->start)) {
+ fprintf(stderr, "Entry at %td has a bad 'data->start' entry.\n",
+ cursor - data->start);
+ return 1;
}
- return 0;
-}
+ entry->size = u32le(cursor + ENTRY_SIZE);
+ entry->patient_id = u32le(cursor + ENTRY_PATIENT_ID);
+ entry->study_id = u32le(cursor + ENTRY_STUDY_ID);
+ entry->series_id = u32le(cursor + ENTRY_SERIES_ID);
+ entry->slice_id = u32le(cursor + ENTRY_SLICE_ID);
+ entry->type = u32le(cursor + ENTRY_TYPE);
-static int read_chunk(const char *start, const char *end,
- const struct e2e_entry *entry, struct e2e_chunk *chunk)
-{
- const char *cursor = entry->start, *pos;
+ if (!entry->start || entry->start < data->start + HEADER_END)
+ return 0;
+
+ cursor = entry->start;
+ chunk = &entry->chunk;
+ entry->has_chunk = 1;
chunk->entry = entry;
chunk->origin = cursor;
- if (cursor + CHUNK_HEADER_END > end) {
+ if (cursor + CHUNK_HEADER_END > data->end) {
fprintf(stderr, "Chunk at %td ends past the end of file.\n",
- cursor - start);
+ cursor - data->start);
return 1;
}
- if (make_pointer(start, end, cursor + CHUNK_POS, &pos)) {
+ if (make_pointer(data, cursor + CHUNK_POS, &pos)) {
fprintf(stderr, "Chunk at %td has a bad 'pos' entry.\n",
- cursor - start);
+ cursor - data->start);
return 1;
}
if (pos != cursor) {
- fprintf(stderr, "Chunk at %td has a 'pos' entry that differs from the entry's actual position",
- cursor - start);
+ fprintf(stderr, "Chunk at %td has a 'pos' entry that differs from the entry's actual position.\n",
+ cursor - data->start);
return 1;
}
@@ -230,80 +211,75 @@ static int read_chunk(const char *start, const char *end,
chunk->series_id = u32le(cursor + CHUNK_SERIES_ID);
chunk->slice_id = u32le(cursor + CHUNK_SLICE_ID);
chunk->type = u32le(cursor + CHUNK_TYPE);
+ cursor += CHUNK_HEADER_END;
+
+ switch (chunk->type) {
+ case CHUNK_IMAGE:
+ return read_image(data, cursor, &chunk->image);
+ }
return 0;
}
-static int read_entry(const char *start, const char *end,
- const char *cursor, struct e2e_entry *entry)
+static int read_directory(struct e2e_data *data, const char *cursor,
+ struct e2e_directory *dir)
{
- const char *pos;
-
- if (cursor + ENTRY_END > end) {
- fprintf(stderr, "Entry at %td ends past the end of file.\n",
- cursor - start);
+ if (cursor + DIRECTORY_END > data->end) {
+ fprintf(stderr, "Directory at %td data->ends past the data->end of file.\n",
+ cursor - data->start);
return 1;
}
- if (make_pointer(start, end, cursor + ENTRY_POS, &pos)) {
- fprintf(stderr, "Entry at %td has a bad 'pos' entry.\n",
- cursor - start);
- return 1;
- }
+ dir->num_entries = u32le(cursor + DIRECTORY_NUM_ENTRIES);
- if (pos != cursor) {
- fprintf(stderr, "Entry at %td has a 'pos' entry that differs from the entry's actual position",
- cursor - start);
+ if (make_pointer(data, cursor + DIRECTORY_CURRENT, &dir->current)) {
+ fprintf(stderr, "Directory at %td contains a bad 'current' field.\n",
+ cursor - data->start);
return 1;
}
- if (make_pointer(start, end, cursor + ENTRY_START, &entry->start)) {
- fprintf(stderr, "Entry at %td has a bad 'start' entry.\n",
- cursor - start);
+ if (make_pointer(data, cursor + DIRECTORY_NEXT, &dir->next)) {
+ fprintf(stderr, "Directory at %td contains a bad 'current' field.\n",
+ cursor - data->start);
return 1;
}
- entry->size = u32le(cursor + ENTRY_SIZE);
- entry->patient_id = u32le(cursor + ENTRY_PATIENT_ID);
- entry->study_id = u32le(cursor + ENTRY_STUDY_ID);
- entry->series_id = u32le(cursor + ENTRY_SERIES_ID);
- entry->slice_id = u32le(cursor + ENTRY_SLICE_ID);
- entry->type = u32le(cursor + ENTRY_TYPE);
-
return 0;
}
-static int read_directory(const char *start, const char *end,
- const char *cursor, struct e2e_directory *dir)
+// Because entries are a part of a larger array in e2e_data, they're freed
+// all at once by e2e_destroy and not here.
+void e2e_entry_destroy(struct e2e_entry *entry)
{
- if (cursor + DIRECTORY_END > end) {
- fprintf(stderr, "Directory at %td ends past the end of file.\n",
- cursor - start);
- return 1;
- }
+ if (entry->has_chunk
+ && entry->chunk.type == CHUNK_IMAGE
+ && entry->chunk.image.type == IMAGE_TOMOGRAM)
+ free(entry->chunk.image.tomogram);
+}
- dir->num_entries = u32le(cursor + DIRECTORY_NUM_ENTRIES);
+void e2e_destroy(struct e2e_data *data)
+{
+ struct e2e_directory *dir, *next;
- if (make_pointer(start, end, cursor + DIRECTORY_CURRENT, &dir->current)) {
- fprintf(stderr, "Directory at %td contains a bad 'current' field.\n",
- cursor - start);
- return 1;
- }
+ for (dir = data->dirs; dir; dir = next) {
+ next = dir->data_list.next;
- if (make_pointer(start, end, cursor + DIRECTORY_NEXT, &dir->next)) {
- fprintf(stderr, "Directory at %td contains a bad 'current' field.\n",
- cursor - start);
- return 1;
+ for (size_t i = 0; i < dir->num_entries; i++)
+ e2e_entry_destroy(dir->entries + i);
+ free(dir->entries);
+ free(dir);
}
-
- return 0;
}
-int e2e_read(const char *start, const char *end)
+int e2e_read(struct e2e_data *data, const char *start, const char *end)
{
- int rv;
+ int rv = 0;
const char *cursor;
+ data->start = start;
+ data->end = end;
+ data->dirs = NULL;
+
if (start + HEADER_END > end) {
fprintf(stderr, "File too short to be an E2E file.\n");
return 1;
@@ -315,49 +291,53 @@ int e2e_read(const char *start, const char *end)
cursor += DIRECTORY_END; // skip the first directory (wtf?)
while (cursor) {
- struct e2e_directory dir;
+ struct e2e_directory *dir;
+ size_t i;
+
+ dir = malloc(sizeof(struct e2e_directory));
+ if (!dir) {
+ rv = ENOMEM;
+ goto error;
+ }
- rv = read_directory(start, end, cursor, &dir);
+ rv = read_directory(data, cursor, dir);
if (rv)
- return rv;
+ goto error_read_directory;
- printf("# %08tx Directory: num_entries=%zu, current=%08td, next=%td\n",
- cursor - start, dir.num_entries, dir.current - start,
- dir.next ? dir.next - start : 0);
+ dir->entries = calloc(dir->num_entries, sizeof(struct e2e_entry));
+ if (!dir->entries) {
+ rv = ENOMEM;
+ goto error_alloc_entries;
+ }
- for (size_t i = 0; i < dir.num_entries; i++) {
+ for (i = 0; i < dir->num_entries; i++) {
const char *entry_cursor;
- struct e2e_entry entry;
- struct e2e_chunk chunk;
+ struct e2e_entry *entry = dir->entries + i;
entry_cursor = cursor + DIRECTORY_END + i * ENTRY_END;
- rv = read_entry(start, end, entry_cursor, &entry);
- if (rv)
- return rv;
-
- printf("# %08tx Entry %zu: start=%08tx\n",
- entry_cursor - start, i,
- entry.start ? entry.start - start : 0);
-
- if (!entry.start)
- continue;
-
- rv = read_chunk(start, end, &entry, &chunk);
+ rv = read_entry(data, entry_cursor, entry);
if (rv)
- continue;
+ goto error_read_entry;
+ }
- printf("# %08tx Chunk, size=%zu, type=%08x\n",
- entry.start - start, chunk.size, chunk.type);
+ eli_append(&data->dirs, dir, data_list);
+ cursor = dir->next;
+ continue;
- switch (chunk.type) {
- case DATA_IMAGE:
- read_image(start, end, &chunk);
- break;
- }
- }
- cursor = dir.next;
+ error_read_entry:
+ for (size_t j = 0; j < i; j++)
+ e2e_entry_destroy(dir->entries + j);
+ free(dir->entries);
+ error_alloc_entries:
+ error_read_directory:
+ free(dir);
+ goto error;
}
return 0;
-} \ No newline at end of file
+
+error:
+ e2e_destroy(data);
+ return rv;
+}
diff --git a/src/e2e.h b/src/e2e.h
index d7f7a13..167a83a 100644
--- a/src/e2e.h
+++ b/src/e2e.h
@@ -1,3 +1,64 @@
#include <inttypes.h>
+#include "eli.h"
-int e2e_read(const char *start, const char *end); \ No newline at end of file
+#define IMAGE_FUNDUS 0x02010201
+#define IMAGE_TOMOGRAM 0x02200201
+
+struct e2e_image {
+ size_t size, width, height;
+ uint32_t type;
+
+ union {
+ const uint8_t *fundus;
+ float *tomogram;
+ };
+};
+
+#define CHUNK_IMAGE 0x40000000
+
+struct e2e_chunk {
+ const char *origin;
+ const struct e2e_entry *entry;
+
+ size_t size;
+ uint32_t patient_id, study_id, series_id, slice_id, ind;
+ uint32_t type;
+
+ union {
+ struct e2e_image image;
+ };
+};
+
+struct e2e_entry {
+ const char *start;
+ size_t size;
+
+ uint32_t patient_id, study_id, series_id, slice_id, type;
+
+ _Bool has_chunk;
+ struct e2e_chunk chunk;
+};
+
+struct e2e_fundus {
+ size_t size, width, height;
+
+ uint32_t type;
+};
+
+struct e2e_directory {
+ const char *current, *next;
+
+ size_t num_entries;
+ struct e2e_entry *entries;
+
+ eli_header data_list;
+};
+
+struct e2e_data {
+ const char *start, *end;
+
+ struct e2e_directory *dirs;
+};
+
+int e2e_read(struct e2e_data *data, const char *start, const char *end);
+void e2e_destroy(struct e2e_data *data);
diff --git a/src/main.c b/src/main.c
index e51d863..19d2957 100644
--- a/src/main.c
+++ b/src/main.c
@@ -10,15 +10,14 @@
#include "e2e.h"
-uint32_t u32le(const char*);
-
int main(int argc, char **argv)
{
- int rv = 0;
+ int ret = 0;
char *inpath;
int fd;
struct stat st;
void *input;
+ struct e2e_data data;
if (argc < 2) {
fprintf(stderr, "%s [FILE]\n", argv[0]);
@@ -35,21 +34,22 @@ int main(int argc, char **argv)
if (fstat(fd, &st) == -1) {
perror("fstat");
- rv = 1;
+ ret = 1;
goto error_mmap;
}
input = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (!input) {
perror("mmap");
- rv = 1;
+ ret = 1;
goto error_mmap;
}
- e2e_read(input, input + st.st_size);
+ e2e_read(&data, input, input + st.st_size);
+ e2e_destroy(&data);
munmap(input, st.st_size);
error_mmap:
close(fd);
- return rv;
+ return ret;
} \ No newline at end of file