loaders: Added Exif to MetaData parser.
[gfxprim.git] / libs / loaders / GP_MetaData.c
blob1403e0184273a9aba2c2ffad0492eb6dea4ec2e6
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\n", rec->val.r.num, rec->val.r.den);
107 break;
108 case GP_META_STRING:
109 printf("'%s'\n", rec->val.str);
110 break;
111 case GP_META_DOUBLE:
112 printf("%lf\n", rec->val.d);
113 break;
118 static GP_MetaRecord *record_lookup(GP_MetaData *self, const char *id,
119 unsigned int hash)
121 GP_MetaRecord *rec;
123 for (rec = self->root; rec != NULL; rec = rec->next)
124 if (rec->hash == hash && !strcmp(rec->id, id))
125 return rec;
127 return NULL;
130 static void *do_alloc(struct GP_MetaData *self, size_t size)
132 if (self->free < size) {
133 GP_DEBUG(0, "TODO: storage full");
134 return NULL;
137 void *ret = ((char*)self) + sizeof(struct GP_MetaData) + (self->size - self->free);
139 self->free -= size;
141 return ret;
144 static GP_MetaRecord *record_create(GP_MetaData *self, const char *id,
145 unsigned int hash)
147 GP_MetaRecord *rec;
149 if (strlen(id) + 1 > GP_META_RECORD_ID_MAX) {
150 GP_DEBUG(0, "Can't create id '%s' longer than %i chars",
151 id, GP_META_RECORD_ID_MAX - 1);
152 return NULL;
155 rec = do_alloc(self, sizeof(struct GP_MetaRecord));
157 if (rec == NULL)
158 return NULL;
160 strcpy(rec->id, id);
161 rec->hash = hash;
163 if (self->root == NULL) {
164 self->root = rec;
165 self->last = rec;
166 } else {
167 self->last->next = rec;
168 self->last = rec;
169 rec->next = NULL;
172 self->rec_count++;
174 return rec;
177 GP_MetaRecord *GP_MetaDataCreateRecord(GP_MetaData *self, const char *id)
179 unsigned int hash = do_hash(id);
181 if (record_lookup(self, id, hash)) {
182 GP_DEBUG(1, "Trying to create duplicate record id '%s'", id);
183 return NULL;
186 return record_create(self, id, hash);
189 int GP_MetaDataGetInt(GP_MetaData *self, const char *id, int *res)
191 GP_MetaRecord *rec;
193 GP_DEBUG(2, "Looking for GP_META_INT id '%s'", id);
195 rec = record_lookup(self, id, do_hash(id));
197 if (rec == NULL) {
198 GP_DEBUG(3, "Record id '%s' not found", id);
199 return 1;
202 if (rec->type != GP_META_INT) {
203 GP_DEBUG(3, "Record id '%s' has wrong type", id);
204 return 1;
207 *res = rec->val.i;
209 GP_DEBUG(3, "Found GP_META_INT id '%s' = %i", id, *res);
211 return 0;
214 int GP_MetaDataGetDouble(GP_MetaData *self, const char *id, double *res)
216 GP_MetaRecord *rec;
218 GP_DEBUG(2, "Looking for GP_META_DOUBLE id '%s'", id);
220 rec = record_lookup(self, id, do_hash(id));
222 if (rec == NULL) {
223 GP_DEBUG(3, "Record id '%s' not found", id);
224 return 1;
227 if (rec->type != GP_META_DOUBLE) {
228 GP_DEBUG(3, "Record id '%s' has wrong type", id);
229 return 1;
232 *res = rec->val.d;
234 GP_DEBUG(3, "Found GP_META_DOUBLE id '%s' = %lf", id, *res);
236 return 0;
239 const char *GP_MetaDataGetString(GP_MetaData *self, const char *id)
241 GP_MetaRecord *rec;
243 GP_DEBUG(2, "Looking for GP_META_STRING id '%s'", id);
245 rec = record_lookup(self, id, do_hash(id));
247 if (rec == NULL) {
248 GP_DEBUG(3, "Record id '%s' not found", id);
249 return NULL;
252 if (rec->type != GP_META_STRING) {
253 GP_DEBUG(3, "Record id '%s' has wrong type", id);
254 return NULL;
257 GP_DEBUG(3, "Found GP_META_STRING id '%s' = '%s'", id, rec->val.str);
259 return rec->val.str;
262 GP_MetaRecord *GP_MetaDataCreateInt(GP_MetaData *self, const char *id, int val)
264 GP_MetaRecord *rec;
266 GP_DEBUG(2, "Creating GP_META_INT id '%s' = %i", id, val);
268 rec = GP_MetaDataCreateRecord(self, id);
270 if (rec == NULL)
271 return NULL;
273 rec->type = GP_META_INT;
274 rec->val.i = val;
276 return rec;
279 GP_MetaRecord *GP_MetaDataCreateRat(GP_MetaData *self, const char *id,
280 int num, int den)
282 GP_MetaRecord *rec;
284 GP_DEBUG(2, "Creating GP_META_RATIONAL id '%s' = %i/%i", id, num, den);
286 if (den == 0) {
287 GP_DEBUG(1, "Would not create '%s' with denominator == 0", id);
288 return NULL;
291 rec = GP_MetaDataCreateRecord(self, id);
293 if (rec == NULL)
294 return NULL;
296 rec->type = GP_META_RATIONAL;
297 rec->val.r.num = num;
298 rec->val.r.den = den;
300 return rec;
303 GP_MetaRecord *GP_MetaDataCreateDouble(GP_MetaData *self, const char *id,
304 double val)
306 GP_MetaRecord *rec;
308 GP_DEBUG(2, "Creating GP_META_DOUBLE id '%s' = %lf", id, val);
310 rec = GP_MetaDataCreateRecord(self, id);
312 if (rec == NULL)
313 return NULL;
315 rec->type = GP_META_DOUBLE;
316 rec->val.d = val;
318 return rec;
321 GP_MetaRecord *GP_MetaDataCreateString(GP_MetaData *self, const char *id,
322 const char *str, int len, int dup)
324 GP_MetaRecord *rec;
326 GP_DEBUG(2, "Creating GP_META_STRING id '%s' = '%s'", id, str);
328 rec = GP_MetaDataCreateRecord(self, id);
330 if (rec == NULL)
331 return NULL;
333 if (dup) {
334 size_t size;
335 char *s;
337 if (len == 0)
338 size = strlen(str) + 1;
339 else
340 size = len + 1;
342 /* Play safe with aligment */
343 if (size % 8)
344 size += 8 - size % 8;
346 //TODO: allocation error
347 s = do_alloc(self, size);
348 strncpy(s, str, size - 1);
349 s[size - 1] = '\0';
350 str = s;
353 rec->type = GP_META_STRING;
354 rec->val.str = str;
356 return rec;