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