libidx-c

C library for IDX file format
git clone https://git.sinitax.com/sinitax/libidx-c
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

commit e08301d5925b11331bade915f5d2668e444c4835
Author: Louis Burda <quent.burda@gmail.com>
Date:   Thu,  7 Apr 2022 12:27:33 +0200

Minimal Working Example

Diffstat:
A.gitignore | 3+++
AMakefile | 41+++++++++++++++++++++++++++++++++++++++++
Ainclude/idx.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alibidx.abi | 9+++++++++
Alibidx.lds | 13+++++++++++++
Asrc/idx.c | 272+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test.c | 28++++++++++++++++++++++++++++
7 files changed, 426 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,3 @@ +.cache +build +compile_commands.json diff --git a/Makefile b/Makefile @@ -0,0 +1,41 @@ +CFLAGS = -I include -g +LDLIBS = +DEPFLAGS = -MT $@ -MMD -MP -MF build/$*.d + +_SRCS = idx.c +SRCS = $(_SRCS:%.c=src/%.c) +OBJS = $(_SRCS:%.c=build/%.o) +DEPS = $(_SRCS:%.c=build/%.d) +PI_OBJS = $(_SRCS:%.c=build/%.pi.o) + +.PHONY: all clean + +all: build/libidx.so build/libidx.a build/test + +clean: + rm -rf build + +build: + mkdir build + +build/%.o: src/%.c build/%.d | build + $(CC) -c -o $@ $< $(DEPFLAGS) $(CFLAGS) + +build/%.pi.o: src/%.c build/%.d | build + $(CC) -c -o $@ $< $(DEPFLAGS) $(CFLAGS) -fPIC + +build/%.d: | build; + +include $(DEPS) + +build/libidx.a: $(OBJS) | build + $(CC) -o build/tmp.o $^ $(CFLAGS) -r + objcopy --keep-global-symbols=libidx.abi build/tmp.o build/fixed.o + ar rcs $@ build/fixed.o + +build/libidx.so: $(PI_OBJS) | build + $(CC) -o $@ $(PI_OBJS) $(CFLAGS) -shared -Wl,-version-script libidx.lds + +build/test: src/test.c build/libidx.a | build + $(CC) -o $@ $^ $(CFLAGS) + diff --git a/include/idx.h b/include/idx.h @@ -0,0 +1,60 @@ +#pragma once + +#include <stdint.h> +#include <stdlib.h> + +enum { + IDX_TYPE_UNKNOWN = -1, + IDX_TYPE_UNSIGNED_BYTE, + IDX_TYPE_SIGNED_BYTE, + IDX_TYPE_SHORT, + IDX_TYPE_INT, + IDX_TYPE_FLOAT, + IDX_TYPE_DOUBLE, + IDX_TYPE_COUNT, +}; + +enum { + IDX_OK, + IDX_BAD_PARAM, + IDX_FILE_ACCESS, + IDX_FILE_BAD_MAGIC, + IDX_FILE_BAD_TYPE, + IDX_FILE_BAD_DIMS, + IDX_FILE_WRITE_MAGIC, + IDX_FILE_WRITE_DIMS, + IDX_FILE_WRITE_DATA, + IDX_FILE_READ_MAGIC, + IDX_FILE_READ_DIMS, + IDX_FILE_READ_DATA, + IDX_OUT_OF_MEMORY, +}; + +struct idx { + struct { + int val; + uint8_t size; + } type; + + struct { + void *data; + size_t len; + } buf; + + struct { + uint8_t count; + uint32_t *sizes; + } dims; +}; + +int idx_new(struct idx *idx, uint8_t dims_count, uint32_t *dims, int data_type); +int idx_wrap(struct idx *idx, void *data, uint8_t dims_count, + uint32_t *dims, int data_type); + +int idx_load(struct idx *idx, const char *filename); +int idx_save(struct idx *idx, const char *filename); + +void idx_deinit(struct idx *idx); + +void *idx_get(struct idx *idx, int dims, ...); + diff --git a/libidx.abi b/libidx.abi @@ -0,0 +1,9 @@ +idx_new +idx_wrap + +idx_load +idx_save + +idx_deinit + +idx_get diff --git a/libidx.lds b/libidx.lds @@ -0,0 +1,13 @@ +LIBIDX_1.0 { + global: + idx_new; + idx_wrap; + + idx_load; + idx_save; + + idx_deinit; + + idx_get; + local: *; +}; diff --git a/src/idx.c b/src/idx.c @@ -0,0 +1,272 @@ +#include "idx.h" + +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> + +#define ASSERT(x) assert((x), __FILE__, __LINE__, #x) + +static const int idx_type_encode_lut[IDX_TYPE_COUNT] = { + [IDX_TYPE_UNSIGNED_BYTE] = 0x08, + [IDX_TYPE_SIGNED_BYTE] = 0x09, + [IDX_TYPE_SHORT] = 0x0B, + [IDX_TYPE_INT] = 0x0C, + [IDX_TYPE_FLOAT] = 0x0D, + [IDX_TYPE_DOUBLE] = 0x0E, +}; + +static const int idx_type_size[IDX_TYPE_COUNT] = { + [IDX_TYPE_UNSIGNED_BYTE] = 1, + [IDX_TYPE_SIGNED_BYTE] = 1, + [IDX_TYPE_SHORT] = 2, + [IDX_TYPE_INT] = 4, + [IDX_TYPE_FLOAT] = 4, + [IDX_TYPE_DOUBLE] = 8 +}; + +static void assert(bool cond, const char *file, + size_t line, const char *condstr); + +static bool valid_idx_type(int type); + +static int idx_type_decode(int val); + +static bool fread_u32(FILE *f, uint32_t *val); +static bool fwrite_u32(FILE *f, uint32_t val); + +void +assert(bool cond, const char *file, size_t line, const char *condstr) +{ + if (cond) return; + + fprintf(stderr, "LIBIDX: Assertion failed at %s:%li (%s)\n", + file, line, condstr); + + exit(1); +} + +bool +valid_idx_type(int type) +{ + return type >= 0 && type < IDX_TYPE_COUNT; +} + +int +idx_type_decode(int val) +{ + int i; + + for (i = 0; i < IDX_TYPE_COUNT; i++) { + if (val == idx_type_encode_lut[i]) + return i; + } + + return IDX_TYPE_UNKNOWN; +} + +bool +fread_u32(FILE *f, uint32_t *val) +{ + int len; + + len = fread(val, 4, 1, f); + if (len != 1) return false; + *val = be32toh(*val); + + return true; +} + +bool +fwrite_u32(FILE *f, uint32_t val) +{ + int len; + + val = htobe32(val); + len = fwrite(&val, 4, 1, f); + if (len != 1) return false; + + return true; +} + +int +idx_new(struct idx *idx, uint8_t dims_count, uint32_t *dims, int data_type) +{ + size_t i, size; + + if (!valid_idx_type(data_type)) + return IDX_BAD_PARAM; + + size = idx_type_size[data_type]; + for (i = 0; i < dims_count; i++) + size *= dims[i]; + + idx->buf.data = malloc(size); + if (idx->buf.data == NULL) + return IDX_OUT_OF_MEMORY; + idx->buf.len = size; + + idx->dims.sizes = dims; /* move */ + idx->dims.count = dims_count; + + idx->type.size = idx_type_size[data_type]; + idx->type.val = data_type; + + return IDX_OK; +} + +int +idx_wrap(struct idx *idx, void *data, uint8_t dims_count, + uint32_t *dims, int data_type) +{ + size_t i, size; + + if (!valid_idx_type(data_type)) + return IDX_BAD_PARAM; + + size = idx_type_size[data_type]; + for (i = 0; i < dims_count; i++) + size *= dims[i]; + + idx->buf.data = data; /* move */ + idx->buf.len = size; + + idx->dims.sizes = dims; /* move */ + idx->dims.count = dims_count; + + idx->type.size = idx_type_size[data_type]; + idx->type.val = data_type; + + return IDX_OK; +} + +int +idx_load(struct idx *idx, const char *filename) +{ + uint32_t magic; + int len, i; + FILE *file; + + file = fopen(filename, "r"); + if (file == NULL) + return IDX_FILE_ACCESS; + + /* read magic */ + if (!fread_u32(file, &magic)) + return IDX_FILE_READ_MAGIC; + + if ((magic & 0xFFFF0000) != 0) + return IDX_FILE_BAD_MAGIC; + + idx->type.val = idx_type_decode((magic & 0xFF00) >> 8); + if (idx->type.val == IDX_TYPE_UNKNOWN) + return IDX_FILE_BAD_TYPE; + idx->type.size = idx_type_size[idx->type.val]; + + idx->dims.count = magic & 0xFF; + if (idx->dims.count == 0) + return IDX_FILE_BAD_DIMS; + + idx->dims.sizes = malloc(sizeof(uint32_t) * idx->dims.count); + if (idx->dims.sizes == NULL) + return IDX_OUT_OF_MEMORY; + + /* read dims */ + idx->buf.len = 1; + for (i = 0; i < idx->dims.count; i++) { + if (!fread_u32(file, &idx->dims.sizes[i])) + return IDX_FILE_READ_DIMS; + idx->buf.len *= idx->dims.sizes[i]; + } + + idx->buf.data = malloc(idx->buf.len); + if (idx->buf.data == NULL) + return IDX_OUT_OF_MEMORY; + + /* read data */ + len = fread(idx->buf.data, idx->type.size, idx->buf.len, file); + if (len != idx->buf.len) + return IDX_FILE_READ_DATA; + + fclose(file); + + return IDX_OK; +} + +int +idx_save(struct idx *idx, const char *filename) +{ + FILE *file; + uint32_t val; + size_t i, len, size; + + file = fopen(filename, "w+"); + if (file == NULL) + return IDX_FILE_ACCESS; + + if (!valid_idx_type(idx->type.val)) + return IDX_BAD_PARAM; + val = idx_type_encode_lut[idx->type.val]; + + /* write magic */ + if (!fwrite_u32(file, (val << 8) + idx->dims.count)) + return IDX_FILE_WRITE_MAGIC; + + /* write dims */ + for (i = 0; i < idx->dims.count; i++) { + if (!fwrite_u32(file, idx->dims.sizes[i])) + return IDX_FILE_WRITE_DIMS; + } + + size = idx_type_size[idx->type.val]; + for (i = 0; i < idx->dims.count; i++) + size *= idx->dims.sizes[i]; + + /* write data */ + len = fwrite(idx->buf.data, 1, size, file); + if (len != size) return IDX_FILE_WRITE_DATA; + + fclose(file); + + return IDX_OK; +} + +void +idx_deinit(struct idx *idx) +{ + free(idx->buf.data); + free(idx->dims.sizes); +} + +void * +idx_get(struct idx *idx, int dims, ...) +{ + va_list ap; + size_t stride; + int i, val; + void *p; + + if (dims < 0 || dims > idx->dims.count) + return NULL; + + stride = 1; + for (i = 0; i < idx->dims.count; i++) + stride *= idx->dims.sizes[i]; + + p = idx->buf.data; + va_start(ap, dims); + for (i = 0; i < dims; i++) { + val = va_arg(ap, int); + if (val >= idx->dims.sizes[i]) + return NULL; + + stride /= idx->dims.sizes[i]; + p += stride * val; + } + va_end(ap); + + return p; +} + + diff --git a/src/test.c b/src/test.c @@ -0,0 +1,28 @@ +#include "idx.h" + +#include <stdio.h> + +int +main(int argc, const char **argv) +{ + struct idx data; + int i, status; + uint8_t *p; + + status = idx_load(&data, argv[1]); + if (status != IDX_OK) { + printf("Failed to load file: %i\n", status); + return 1; + } + + printf("DIMS: "); + for (i = 0; i < data.dims.count; i++) + printf("%s%i", i ? " x " : "", data.dims.sizes[i]); + printf("\n"); + + printf("Value at 10 x 10 x 10: "); + p = idx_get(&data, 3, 10, 10, 10); + printf("%02X\n", p ? *p : 0); + + idx_deinit(&data); +}