filters: Add generated Nearest Neighbour filter.
[gfxprim.git] / libs / loaders / GP_MetaData.c
bloba81480f1d58182dcce519f8542c977882b1d9445
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2012 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include <stdlib.h>
24 #include <string.h>
26 #include "core/GP_Debug.h"
28 #include "GP_MetaData.h"
30 struct GP_MetaData {
31 struct GP_MetaRecord *root;
32 struct GP_MetaRecord *last;
33 unsigned int rec_count;
34 size_t size;
35 size_t free;
36 char buf[];
39 static unsigned int do_hash(const char *id)
41 unsigned int hash = 0;
43 while (*id != '\0') {
44 hash += *id * 1217;
45 hash %= 46309;
46 id += 1;
49 return hash;
52 GP_MetaData *GP_MetaDataCreate(unsigned int expected_records)
54 GP_MetaData *data;
55 size_t size = expected_records * sizeof(struct GP_MetaRecord);
57 GP_DEBUG(1, "Creating MetaData for %u records", expected_records);
59 data = malloc(sizeof(struct GP_MetaData) + size);
61 if (data == NULL) {
62 GP_DEBUG(1, "Malloc failed :(");
63 return NULL;
66 data->root = NULL;
67 data->last = NULL;
68 data->rec_count = 0;
69 data->size = size;
70 data->free = size;
72 return data;
75 void GP_MetaDataClear(GP_MetaData *self)
77 GP_DEBUG(1, "Clearing MetaData %p with %u records",
78 self, self->rec_count);
80 self->root = NULL;
81 self->last = NULL;
82 self->rec_count = 0;
83 self->free = self->size;
86 void GP_MetaDataDestroy(GP_MetaData *self)
88 GP_DEBUG(1, "Destroying MetaData %p", self);
89 free(self);
92 void GP_MetaDataPrint(GP_MetaData *self)
94 GP_MetaRecord *rec;
96 printf("MetaData %u record(s)\n", self->rec_count);
98 for (rec = self->root; rec != NULL; rec = rec->next) {
99 printf("%-32s: ", rec->id);
101 switch (rec->type) {
102 case GP_META_INT:
103 printf("%i\n", rec->val.i);
104 break;
105 case GP_META_RATIONAL:
106 printf("%i/%i (%.4f)\n", rec->val.r.num, rec->val.r.den,
107 (float)rec->val.r.num / rec->val.r.den);
108 break;
109 case GP_META_STRING:
110 printf("'%s'\n", rec->val.str);
111 break;
112 case GP_META_DOUBLE:
113 printf("%lf\n", rec->val.d);
114 break;
119 static GP_MetaRecord *record_lookup(GP_MetaData *self, const char *id,
120 unsigned int hash)
122 GP_MetaRecord *rec;
124 for (rec = self->root; rec != NULL; rec = rec->next)
125 if (rec->hash == hash && !strcmp(rec->id, id))
126 return rec;
128 return NULL;
131 static void *do_alloc(struct GP_MetaData *self, size_t size)
133 if (self->free < size) {
134 GP_DEBUG(0, "TODO: storage full");
135 return NULL;
138 void *ret = ((char*)self) + sizeof(struct GP_MetaData) + (self->size - self->free);
140 self->free -= size;
142 return ret;
145 static GP_MetaRecord *record_create(GP_MetaData *self, const char *id,
146 unsigned int hash)
148 GP_MetaRecord *rec;
150 if (strlen(id) + 1 > GP_META_RECORD_ID_MAX) {
151 GP_DEBUG(0, "Can't create id '%s' longer than %i chars",
152 id, GP_META_RECORD_ID_MAX - 1);
153 return NULL;
156 rec = do_alloc(self, sizeof(struct GP_MetaRecord));
158 if (rec == NULL)
159 return NULL;
161 strcpy(rec->id, id);
162 rec->hash = hash;
163 rec->next = NULL;
165 if (self->root == NULL) {
166 self->root = rec;
167 self->last = rec;
168 } else {
169 self->last->next = rec;
170 self->last = rec;
173 self->rec_count++;
175 return rec;
178 GP_MetaRecord *GP_MetaDataCreateRecord(GP_MetaData *self, const char *id)
180 unsigned int hash = do_hash(id);
182 if (record_lookup(self, id, hash)) {
183 GP_DEBUG(1, "Trying to create duplicate record id '%s'", id);
184 return NULL;
187 return record_create(self, id, hash);
190 int GP_MetaDataGetInt(GP_MetaData *self, const char *id, int *res)
192 GP_MetaRecord *rec;
194 GP_DEBUG(2, "Looking for GP_META_INT id '%s'", id);
196 rec = record_lookup(self, id, do_hash(id));
198 if (rec == NULL) {
199 GP_DEBUG(3, "Record id '%s' not found", id);
200 return 1;
203 if (rec->type != GP_META_INT) {
204 GP_DEBUG(3, "Record id '%s' has wrong type", id);
205 return 1;
208 *res = rec->val.i;
210 GP_DEBUG(3, "Found GP_META_INT id '%s' = %i", id, *res);
212 return 0;
215 int GP_MetaDataGetDouble(GP_MetaData *self, const char *id, double *res)
217 GP_MetaRecord *rec;
219 GP_DEBUG(2, "Looking for GP_META_DOUBLE id '%s'", id);
221 rec = record_lookup(self, id, do_hash(id));
223 if (rec == NULL) {
224 GP_DEBUG(3, "Record id '%s' not found", id);
225 return 1;
228 if (rec->type != GP_META_DOUBLE) {
229 GP_DEBUG(3, "Record id '%s' has wrong type", id);
230 return 1;
233 *res = rec->val.d;
235 GP_DEBUG(3, "Found GP_META_DOUBLE id '%s' = %lf", id, *res);
237 return 0;
240 const char *GP_MetaDataGetString(GP_MetaData *self, const char *id)
242 GP_MetaRecord *rec;
244 GP_DEBUG(2, "Looking for GP_META_STRING id '%s'", id);
246 rec = record_lookup(self, id, do_hash(id));
248 if (rec == NULL) {
249 GP_DEBUG(3, "Record id '%s' not found", id);
250 return NULL;
253 if (rec->type != GP_META_STRING) {
254 GP_DEBUG(3, "Record id '%s' has wrong type", id);
255 return NULL;
258 GP_DEBUG(3, "Found GP_META_STRING id '%s' = '%s'", id, rec->val.str);
260 return rec->val.str;
263 GP_MetaRecord *GP_MetaDataCreateInt(GP_MetaData *self, const char *id, int val)
265 GP_MetaRecord *rec;
267 GP_DEBUG(2, "Creating GP_META_INT id '%s' = %i", id, val);
269 rec = GP_MetaDataCreateRecord(self, id);
271 if (rec == NULL)
272 return NULL;
274 rec->type = GP_META_INT;
275 rec->val.i = val;
277 return rec;
280 GP_MetaRecord *GP_MetaDataCreateRat(GP_MetaData *self, const char *id,
281 int num, int den)
283 GP_MetaRecord *rec;
285 GP_DEBUG(2, "Creating GP_META_RATIONAL id '%s' = %i/%i", id, num, den);
287 if (den == 0) {
288 GP_DEBUG(1, "Would not create '%s' with denominator == 0", id);
289 return NULL;
292 rec = GP_MetaDataCreateRecord(self, id);
294 if (rec == NULL)
295 return NULL;
297 rec->type = GP_META_RATIONAL;
298 rec->val.r.num = num;
299 rec->val.r.den = den;
301 return rec;
304 GP_MetaRecord *GP_MetaDataCreateDouble(GP_MetaData *self, const char *id,
305 double val)
307 GP_MetaRecord *rec;
309 GP_DEBUG(2, "Creating GP_META_DOUBLE id '%s' = %lf", id, val);
311 rec = GP_MetaDataCreateRecord(self, id);
313 if (rec == NULL)
314 return NULL;
316 rec->type = GP_META_DOUBLE;
317 rec->val.d = val;
319 return rec;
322 GP_MetaRecord *GP_MetaDataCreateString(GP_MetaData *self, const char *id,
323 const char *str, int len, int dup)
325 GP_MetaRecord *rec;
327 GP_DEBUG(2, "Creating GP_META_STRING id '%s' = '%s'", id, str);
329 rec = GP_MetaDataCreateRecord(self, id);
331 if (rec == NULL)
332 return NULL;
334 if (dup) {
335 size_t size;
336 char *s;
338 if (len == 0)
339 len = strlen(str);
341 size = len + 1;
343 /* Play safe with aligment */
344 if (size % 8)
345 size += 8 - size % 8;
347 //TODO: allocation error
348 s = do_alloc(self, size);
349 memcpy(s, str, len);
350 s[len] = '\0';
351 str = s;
354 rec->type = GP_META_STRING;
355 rec->val.str = str;
357 return rec;