libidx-c

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

idx.c (5180B)


      1#define _DEFAULT_SOURCE
      2
      3#include "idx.h"
      4
      5#include <endian.h>
      6#include <stdbool.h>
      7#include <stdio.h>
      8#include <stdint.h>
      9#include <stdarg.h>
     10
     11static const uint8_t idx_type_encode_lut[IDX_TYPE_COUNT] = {
     12	[IDX_TYPE_UNSIGNED_BYTE] = 0x08,
     13	[IDX_TYPE_SIGNED_BYTE] = 0x09,
     14	[IDX_TYPE_SHORT] = 0x0B,
     15	[IDX_TYPE_INT] = 0x0C,
     16	[IDX_TYPE_FLOAT] = 0x0D,
     17	[IDX_TYPE_DOUBLE] = 0x0E,
     18};
     19
     20static const uint8_t idx_type_size[IDX_TYPE_COUNT] = {
     21	[IDX_TYPE_UNSIGNED_BYTE] = 1,
     22	[IDX_TYPE_SIGNED_BYTE] = 1,
     23	[IDX_TYPE_SHORT] = 2,
     24	[IDX_TYPE_INT] = 4,
     25	[IDX_TYPE_FLOAT] = 4,
     26	[IDX_TYPE_DOUBLE] = 8
     27};
     28
     29static bool valid_idx_type(int type);
     30
     31static int idx_type_decode(int val);
     32
     33static bool fread_u32(FILE *f, uint32_t *val);
     34static bool fwrite_u32(FILE *f, uint32_t val);
     35
     36bool
     37valid_idx_type(int type)
     38{
     39	return type >= 0 && type < IDX_TYPE_COUNT;
     40}
     41
     42int
     43idx_type_decode(int val)
     44{
     45	int i;
     46
     47	for (i = 0; i < IDX_TYPE_COUNT; i++) {
     48		if (val == idx_type_encode_lut[i])
     49			return i;
     50	}
     51
     52	return IDX_TYPE_UNKNOWN;
     53}
     54
     55bool
     56fread_u32(FILE *f, uint32_t *val)
     57{
     58	size_t len;
     59
     60	len = fread(val, 4, 1, f);
     61	if (len != 1) return false;
     62	*val = be32toh(*val);
     63
     64	return true;
     65}
     66
     67bool
     68fwrite_u32(FILE *f, uint32_t val)
     69{
     70	size_t len;
     71
     72	val = htobe32(val);
     73	len = fwrite(&val, 4, 1, f);
     74	if (len != 1) return false;
     75
     76	return true;
     77}
     78
     79int
     80idx_new(struct idx *idx, uint8_t dims_count, uint32_t *dims, int data_type,
     81	const struct allocator *allocator)
     82{
     83	size_t i, size;
     84	int rc;
     85
     86	if (!valid_idx_type(data_type))
     87		return IDX_BAD_PARAM;
     88
     89	size = idx_type_size[data_type];
     90	for (i = 0; i < dims_count; i++)
     91		size *= dims[i];
     92
     93	idx->allocator = allocator;
     94	idx->buf.data = allocator->alloc(allocator, size, &rc);
     95	if (!idx->buf.data) return -rc;
     96	idx->buf.len = size;
     97
     98	idx->dims.sizes = dims; /* move */
     99	idx->dims.count = dims_count;
    100
    101	idx->type.size = idx_type_size[data_type];
    102	idx->type.val = data_type;
    103
    104	return IDX_OK;
    105}
    106
    107int
    108idx_wrap(struct idx *idx, void *data, uint8_t dims_count,
    109	uint32_t *dims, int data_type)
    110{
    111	size_t i, size;
    112
    113	if (!valid_idx_type(data_type))
    114		return IDX_BAD_PARAM;
    115
    116	size = idx_type_size[data_type];
    117	for (i = 0; i < dims_count; i++)
    118		size *= dims[i];
    119
    120	idx->allocator = NULL;
    121
    122	idx->buf.data = data; /* move */
    123	idx->buf.len = size;
    124
    125	idx->dims.sizes = dims; /* move */
    126	idx->dims.count = dims_count;
    127
    128	idx->type.size = idx_type_size[data_type];
    129	idx->type.val = data_type;
    130
    131	return IDX_OK;
    132}
    133
    134int
    135idx_load(struct idx *idx, const char *filename,
    136	const struct allocator *allocator)
    137{
    138	uint32_t magic;
    139	size_t len, i;
    140	FILE *file;
    141	int rc;
    142
    143	file = fopen(filename, "r");
    144	if (file == NULL)
    145		return IDX_FILE_ACCESS;
    146
    147	/* read magic */
    148	if (!fread_u32(file, &magic))
    149		return IDX_FILE_READ_MAGIC;
    150
    151	if ((magic & 0xFFFF0000) != 0)
    152		return IDX_FILE_BAD_MAGIC;
    153
    154	idx->type.val = idx_type_decode((magic & 0xFF00) >> 8);
    155	if (idx->type.val == IDX_TYPE_UNKNOWN)
    156		return IDX_FILE_BAD_TYPE;
    157	idx->type.size = idx_type_size[idx->type.val];
    158
    159	idx->dims.count = magic & 0xFF;
    160	if (idx->dims.count == 0)
    161		return IDX_FILE_BAD_DIMS;
    162
    163	idx->allocator = allocator;
    164	idx->dims.sizes = allocator->alloc(allocator,
    165		sizeof(uint32_t) * idx->dims.count, &rc);
    166	if (!idx->dims.sizes) return -rc;
    167
    168	/* read dims */
    169	idx->buf.len = 1;
    170	for (i = 0; i < idx->dims.count; i++) {
    171		if (!fread_u32(file, &idx->dims.sizes[i]))
    172			return IDX_FILE_READ_DIMS;
    173		idx->buf.len *= idx->dims.sizes[i];
    174	}
    175
    176	idx->buf.data = allocator->alloc(allocator, idx->buf.len, &rc);
    177	if (idx->buf.data) return -rc;
    178
    179	/* read data */
    180	len = fread(idx->buf.data, idx->type.size, idx->buf.len, file);
    181	if (len != idx->buf.len)
    182		return IDX_FILE_READ_DATA;
    183
    184	fclose(file);
    185
    186	return IDX_OK;
    187}
    188
    189int
    190idx_save(struct idx *idx, const char *filename)
    191{
    192	FILE *file;
    193	uint32_t val;
    194	size_t i, len, size;
    195
    196	file = fopen(filename, "w+");
    197	if (file == NULL)
    198		return IDX_FILE_ACCESS;
    199
    200	if (!valid_idx_type(idx->type.val))
    201		return IDX_BAD_PARAM;
    202	val = idx_type_encode_lut[idx->type.val];
    203
    204	/* write magic */
    205	if (!fwrite_u32(file, (val << 8) + idx->dims.count))
    206		return IDX_FILE_WRITE_MAGIC;
    207
    208	/* write dims */
    209	for (i = 0; i < idx->dims.count; i++) {
    210		if (!fwrite_u32(file, idx->dims.sizes[i]))
    211			return IDX_FILE_WRITE_DIMS;
    212	}
    213
    214	size = idx_type_size[idx->type.val];
    215	for (i = 0; i < idx->dims.count; i++)
    216		size *= idx->dims.sizes[i];
    217
    218	/* write data */
    219	len = fwrite(idx->buf.data, 1, size, file);
    220	if (len != size) return IDX_FILE_WRITE_DATA;
    221
    222	fclose(file);
    223
    224	return IDX_OK;
    225}
    226
    227int
    228idx_deinit(struct idx *idx)
    229{
    230	int rc;
    231
    232	if (!idx->allocator) return IDX_OK;
    233
    234	rc = idx->allocator->free(idx->allocator, idx->buf.data);
    235	if (rc) return -rc;
    236
    237	rc = idx->allocator->free(idx->allocator, idx->dims.sizes);
    238	if (rc) return -rc;
    239
    240	return IDX_OK;
    241}
    242
    243void *
    244idx_get(struct idx *idx, int dims, ...)
    245{
    246	va_list ap;
    247	size_t stride;
    248	size_t i, val;
    249	void *p;
    250
    251	if (dims < 0 || dims > idx->dims.count)
    252		return NULL;
    253
    254	stride = 1;
    255	for (i = 0; i < idx->dims.count; i++)
    256		stride *= idx->dims.sizes[i];
    257
    258	p = idx->buf.data;
    259	va_start(ap, dims);
    260	for (i = 0; i < dims; i++) {
    261		val = va_arg(ap, size_t);
    262		if (val >= idx->dims.sizes[i])
    263			return NULL;
    264
    265		stride /= idx->dims.sizes[i];
    266		p += stride * val;
    267	}
    268	va_end(ap);
    269
    270	return p;
    271}
    272
    273