diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/e2e.c | 363 | ||||
| -rw-r--r-- | src/e2e.h | 3 | ||||
| -rw-r--r-- | src/main.c | 55 | 
3 files changed, 421 insertions, 0 deletions
diff --git a/src/e2e.c b/src/e2e.c new file mode 100644 index 0000000..1ab1449 --- /dev/null +++ b/src/e2e.c @@ -0,0 +1,363 @@ +#include <stdio.h> +#include <string.h> +#include <math.h> +#include "e2e.h" + +uint32_t u32le(const char *src) +{ +	uint8_t bytes[4]; + +	memcpy(bytes, src, 4); + +	return (uint32_t)bytes[0] +	       + (((uint32_t)bytes[1]) << 8) +	       + (((uint32_t)bytes[2]) << 16) +	       + (((uint32_t)bytes[3]) << 24); +} + +static int make_pointer(const char *start, const char *end, +                        const char *pos, const char **out) +{ +	uint32_t ptroffs; + +	ptroffs = u32le(pos); + +	if (!ptroffs) +		*out = NULL; +	else { +		if (ptroffs > end - start) +			return 1; + +		*out = start + ptroffs; +	} + +	return 0; +} + +#define HEADER_END 36 + +#define DIRECTORY_NUM_ENTRIES   36 +#define DIRECTORY_CURRENT       40 +#define DIRECTORY_NEXT          44 +#define DIRECTORY_END          52 + +#define ENTRY_POS          0 +#define ENTRY_START        4  +#define ENTRY_SIZE         8 +#define ENTRY_PATIENT_ID   16 +#define ENTRY_STUDY_ID     20 +#define ENTRY_SERIES_ID    24 +#define ENTRY_SLICE_ID     28 +#define ENTRY_TYPE         36 +#define ENTRY_END          44 + +#define CHUNK_POS          20 +#define CHUNK_SIZE         24 +#define CHUNK_PATIENT_ID   32 +#define CHUNK_STUDY_ID     36 +#define CHUNK_SERIES_ID    40 +#define CHUNK_SLICE_ID     44 +#define CHUNK_IND          48 +#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 + +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) +{ +	FILE *fp; +	char buffer[1024]; + +	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; + +			memcpy(&px, cursor + y * width + x, 1); +			fprintf(fp, "%s% 3hhu", x ? ", " : "", px); +		} +		fprintf(fp, "]%s\n", y + 1 >= height ? "" : ","); +	} +	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) +{ +	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; + +			memcpy(&raw, cursor + (y * width + x) * 2, 2); + +			man = raw & UF16_MANTISSA_MASK; +			exp = (raw & ~UF16_MANTISSA_MASK) >> 10; + +			px = man * exp2f(exp); +			fprintf(fp, "%s%e", x ? ", " : "", px); +		} +		fprintf(fp, "]%s\n", y + 1 >= height ? "" : ","); +	} +	fprintf(fp, "]\n"); + +	fclose(fp); +	return 0; +} + +static int read_image(const char *start, const char *end, +                      const struct e2e_chunk *chunk) +{ +	const char *cursor = chunk->origin + CHUNK_HEADER_END; +	size_t size, width, height; +	uint32_t type; + +	if (cursor + IMAGE_IMAGE > end) { +		fprintf(stderr, "Image data at %td ends past the end of file.\n", +		        cursor - 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); + +	switch (type) { +	case IMAGE_FUNDUS: +		read_fundus(start, end, cursor + IMAGE_IMAGE, width, height); +		break; + +	case IMAGE_TOMOGRAM: +		read_tomogram(start, end, cursor + IMAGE_IMAGE, width, height); +		break; +	} + +	return 0; +} + +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; + +	chunk->entry = entry; +	chunk->origin = cursor; + +	if (cursor + CHUNK_HEADER_END > end) { +		fprintf(stderr, "Chunk at %td ends past the end of file.\n", +		        cursor - start); +		return 1; +	} + +	if (make_pointer(start, end, cursor + CHUNK_POS, &pos)) { +		fprintf(stderr, "Chunk at %td has a bad 'pos' entry.\n", +		        cursor - 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); +		return 1; +	} + +	chunk->size = u32le(cursor + CHUNK_SIZE); +	chunk->patient_id = u32le(cursor + CHUNK_PATIENT_ID); +	chunk->study_id = u32le(cursor + CHUNK_STUDY_ID); +	chunk->series_id = u32le(cursor + CHUNK_SERIES_ID); +	chunk->slice_id = u32le(cursor + CHUNK_SLICE_ID); +	chunk->type = u32le(cursor + CHUNK_TYPE); + +	return 0; +} + +static int read_entry(const char *start, const char *end, +                      const char *cursor, struct e2e_entry *entry) +{ +	const char *pos; + +	if (cursor + ENTRY_END > end) { +		fprintf(stderr, "Entry at %td ends past the end of file.\n", +		        cursor - 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; +	} + +	if (pos != cursor) { +		fprintf(stderr, "Entry at %td has a 'pos' entry that differs from the entry's actual position", +		        cursor - 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); +		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) +{ +	if (cursor + DIRECTORY_END > end) { +		fprintf(stderr, "Directory at %td ends past the end of file.\n", +		        cursor - start); +		return 1; +	} + +	dir->num_entries = u32le(cursor + DIRECTORY_NUM_ENTRIES); + +	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; +	} + +	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; +	} + +	return 0; +} + +int e2e_read(const char *start, const char *end) +{ +	int rv; +	const char *cursor; + +	if (start + HEADER_END > end) { +		fprintf(stderr, "File too short to be an E2E file.\n"); +		return 1; +	} + +	// TODO: verify the header + +	cursor = start + HEADER_END; +	cursor += DIRECTORY_END; // skip the first directory (wtf?) + +	while (cursor) { +		struct e2e_directory dir; + +		rv = read_directory(start, end, cursor, &dir); +		if (rv) +			return rv; + +		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); + +		for (size_t i = 0; i < dir.num_entries; i++) { +			const char *entry_cursor; +			struct e2e_entry entry; +			struct e2e_chunk chunk; + +			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); +			if (rv) +				continue; + +			printf("# %08tx     Chunk, size=%zu, type=%08x\n", +			       entry.start - start, chunk.size, chunk.type); + +			switch (chunk.type) { +			case DATA_IMAGE: +				read_image(start, end, &chunk); +				break; +			} +		} + +		cursor = dir.next; +	} + +	return 0; +}
\ No newline at end of file diff --git a/src/e2e.h b/src/e2e.h new file mode 100644 index 0000000..d7f7a13 --- /dev/null +++ b/src/e2e.h @@ -0,0 +1,3 @@ +#include <inttypes.h> + +int e2e_read(const char *start, const char *end);
\ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e51d863 --- /dev/null +++ b/src/main.c @@ -0,0 +1,55 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include "e2e.h" + +uint32_t u32le(const char*); + +int main(int argc, char **argv) +{ +	int rv = 0; +	char *inpath; +	int fd; +	struct stat st; +	void *input; + +	if (argc < 2) { +		fprintf(stderr, "%s [FILE]\n", argv[0]); +		return 1; +	} + +	inpath = argv[1]; + +	fd = open(inpath, O_RDONLY); +	if (fd == -1) { +		perror("open"); +		return 1; +	} + +	if (fstat(fd, &st) == -1) { +		perror("fstat"); +		rv = 1; +		goto error_mmap; +	} + +	input = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); +	if (!input) { +		perror("mmap"); +		rv = 1; +		goto error_mmap; +	} + +	e2e_read(input, input + st.st_size); + +	munmap(input, st.st_size); +error_mmap: +	close(fd); +	return rv; +}
\ No newline at end of file  | 
