loaders: JPG: Fix bussy loop on corrupted file.
[gfxprim.git] / libs / loaders / GP_DataStorage.c
blob9210d724b383b602f47469c4c794a24b008391da
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-2015 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "core/GP_Debug.h"
28 #include "core/GP_Common.h"
30 #include "GP_DataStorage.h"
32 struct record {
33 GP_DataNode node;
34 char id[];
37 struct GP_DataDict {
38 struct GP_DataNode *first;
39 struct GP_DataNode *last;
42 #define BLOCK_SIZE 4096
43 #define BLOCK_MAX 128
45 struct block {
46 size_t size;
47 struct block *next;
48 char data[];
51 struct GP_DataStorage {
52 /* Root dictionary */
53 struct GP_DataNode root;
54 struct GP_DataDict dict;
56 /* Block allocator */
57 struct block *blocks;
58 struct block *cur_block;
61 /* Align to four bytes boundary */
62 static size_t align(size_t size)
64 size_t mask = 3;
66 return (size + mask) & ~mask;
69 static struct block *new_block(GP_DataStorage *self, size_t size)
71 struct block *new = malloc(size);
73 GP_DEBUG(3, "Allocating new block for %zu bytes", size);
75 if (!new)
76 return NULL;
78 new->size = size - sizeof(*new);
80 new->next = self->blocks;
81 self->blocks = new;
83 return new;
86 static void *storage_alloc(GP_DataStorage *self, size_t size)
88 struct block *new;
89 void *ret;
91 GP_DEBUG(3, "Allocating %zu bytes", size);
93 if (size >= BLOCK_MAX) {
94 new = new_block(self, sizeof(*new) + size);
96 if (!new)
97 return NULL;
99 return new->data;
102 if (self->cur_block->size < size) {
103 new = new_block(self, BLOCK_SIZE);
105 if (!new)
106 return NULL;
108 self->cur_block = new;
111 ret = self->cur_block->data + BLOCK_SIZE - self->cur_block->size;
112 self->cur_block->size -= size;
114 return ret;
117 static struct record *new_record(GP_DataStorage *self, GP_DataNode *node)
119 size_t id_len = align(strlen(node->id) + 1);
120 size_t payload_len = 0;
121 struct record *new;
122 void *payload;
124 switch (node->type) {
125 case GP_DATA_STRING:
126 payload_len = align(strlen(node->value.str) + 1);
127 break;
128 case GP_DATA_DICT:
129 payload_len = sizeof(struct GP_DataDict);
130 break;
131 default:
132 break;
135 new = storage_alloc(self, sizeof(*new) + id_len + payload_len);
137 if (!new)
138 return NULL;
140 strcpy(new->id, node->id);
141 new->node.id = new->id;
142 new->node.type = node->type;
143 new->node.value = node->value;
144 new->node.next = NULL;
146 payload = ((void*)new) + sizeof(*new) + id_len;
148 switch (node->type) {
149 case GP_DATA_STRING:
150 strcpy(payload, node->value.str);
151 new->node.value.str = payload;
152 break;
153 case GP_DATA_DICT:
154 new->node.value.dict = payload;
155 new->node.value.dict->first = NULL;
156 new->node.value.dict->last = NULL;
157 break;
158 default:
159 break;
162 return new;
165 GP_DataStorage *GP_DataStorageCreate(void)
167 GP_DataStorage *storage = malloc(sizeof(*storage));
169 GP_DEBUG(1, "Creating data storage (%p)", storage);
171 if (!storage)
172 return NULL;
174 storage->root.type = GP_DATA_DICT;
175 storage->root.value.dict = &storage->dict;
176 storage->dict.first = NULL;
177 storage->dict.last = NULL;
179 storage->blocks = NULL;
180 storage->cur_block = new_block(storage, BLOCK_SIZE);
182 if (!storage->cur_block) {
183 free(storage);
184 return NULL;
187 return storage;
190 void GP_DataStorageDestroy(GP_DataStorage *self)
192 struct block *i, *j;
194 if (!self)
195 return;
197 GP_DEBUG(1, "Destroying data storage");
199 for (i = self->blocks; i; ) {
200 j = i->next;
201 free(i);
202 i = j;
205 free(self);
208 void GP_DataStorageClear(GP_DataStorage *self)
210 struct block *i, *j;
212 GP_DEBUG(1, "Clearing all data in storage");
214 /* Clear all but first block */
215 for (i = self->blocks->next; i;) {
216 j = i->next;
217 free(i);
218 i = j;
221 /* Rest first block */
222 self->cur_block = self->blocks;
223 self->cur_block->next = NULL;
224 //TODO: Store block size!!
225 self->cur_block->size = BLOCK_SIZE - sizeof(struct block);
227 /* Reset root dict */
228 self->dict.first = NULL;
229 self->dict.last = NULL;
232 GP_DataNode *GP_DataStorageRoot(GP_DataStorage *self)
234 return &self->root;
237 GP_DataNode *GP_DataDictFirst(GP_DataNode *node)
239 return node->value.dict->first;
242 static void dict_add(GP_DataDict *dict, GP_DataNode *node)
244 if (!dict->last) {
245 dict->first = node;
246 dict->last = node;
247 } else {
248 dict->last->next = node;
249 dict->last = node;
253 GP_DataNode *GP_DataStorageAdd(GP_DataStorage *self,
254 GP_DataNode *node, GP_DataNode *data)
256 struct record *rec;
257 struct GP_DataNode *dup;
259 GP_DEBUG(2, "Adding '%s' to storage (%p)", data->id, self);
261 if (node && node->type != GP_DATA_DICT) {
262 GP_WARN("Trying to insert data into %s",
263 GP_DataTypeName(node->type));
264 return NULL;
267 dup = GP_DataStorageGet(self, node, data->id);
269 if (dup) {
270 GP_WARN("Trying to insert allready existing node '%s'",
271 data->id);
272 return NULL;
275 rec = new_record(self, data);
277 if (!rec)
278 return NULL;
280 if (!node)
281 node = GP_DataStorageRoot(self);
283 dict_add(node->value.dict, &rec->node);
285 return &rec->node;
288 GP_DataNode *GP_DataStorageGet(GP_DataStorage *self,
289 GP_DataNode *node,
290 const char *id)
292 struct GP_DataNode *i;
294 if (!node)
295 node = GP_DataStorageRoot(self);
297 for (i = GP_DataDictFirst(node); i; i = i->next) {
298 if (!strcmp(i->id, id))
299 return i;
302 return NULL;
305 static struct GP_DataNode *lookup(GP_DataNode *node, const char *id,
306 const int id_len)
308 struct GP_DataNode *i;
310 if (!node)
311 return NULL;
313 for (i = GP_DataDictFirst(node); i; i = i->next) {
314 if (!strncmp(i->id, id, id_len))
315 return i;
318 return NULL;
321 static struct GP_DataNode *get_by_path(GP_DataNode *node, const char *path)
323 unsigned int i;
325 for (i = 0; path[i] && path[i] != '/'; i++);
327 if (!i)
328 return node;
330 node = lookup(node, path, i);
332 if (!node)
333 return NULL;
335 GP_DEBUG(3, "Lookup has node '%s'", node->id);
337 if (path[i] == '/')
338 path++;
340 path+=i;
342 return get_by_path(node, path);
345 GP_DataNode *GP_DataStorageGetByPath(GP_DataStorage *self, GP_DataNode *node,
346 const char *path)
348 GP_DEBUG(3, "Looking for '%s' in %p", path, node);
350 if (path[0] == '/') {
352 if (!self)
353 return NULL;
355 node = GP_DataStorageRoot(self);
356 path++;
359 return get_by_path(node, path);
363 static void padd_printf(size_t padd, const char *id, size_t id_padd,
364 const char *fmt, ...)
365 __attribute__ ((format (printf, 4, 5)));
367 static void padd_printf(size_t padd, const char *id, size_t id_padd,
368 const char *fmt, ...)
370 va_list va;
372 while (padd--)
373 fputc(' ', stdout);
375 if (id)
376 fputs(id, stdout);
378 if (id_padd)
379 id_padd -= strlen(id);
381 while (id_padd--)
382 fputc(' ', stdout);
384 va_start(va, fmt);
385 vprintf(fmt, va);
386 va_end(va);
389 /* Must be called on data dict only */
390 static size_t max_id_len(const GP_DataNode *node)
392 size_t max = 0;
393 GP_DataNode *i;
395 for (i = node->value.dict->first; i; i = i->next)
396 max = GP_MAX(max, strlen(i->id));
398 return max;
401 static void data_print(const GP_DataNode *node,
402 unsigned int padd, size_t id_padd)
404 GP_DataNode *i;
406 if (!node) {
407 padd_printf(padd, NULL, 0, "(Empty)\n");
408 return;
411 switch (node->type) {
412 case GP_DATA_INT:
413 padd_printf(padd, node->id, id_padd, " : %li\n", node->value.i);
414 break;
415 case GP_DATA_DOUBLE:
416 padd_printf(padd, node->id, id_padd, " : %lf\n", node->value.d);
417 break;
418 case GP_DATA_RATIONAL:
419 padd_printf(padd, node->id, id_padd, " : %li/%li\n",
420 node->value.rat.num, node->value.rat.den);
421 break;
422 case GP_DATA_STRING:
423 padd_printf(padd, node->id, id_padd, " : '%s'\n", node->value.str);
424 break;
425 case GP_DATA_DICT:
426 padd_printf(padd, node->id ? node->id : "Data Root", 0, " = {\n");
428 for (i = node->value.dict->first; i; i = i->next)
429 data_print(i, padd + 1, max_id_len(node));
431 padd_printf(padd, NULL, 0, "}\n");
432 break;
436 void GP_DataPrint(const GP_DataNode *node)
438 data_print(node, 0, node->id ? strlen(node->id) : 0);
441 const char *GP_DataTypeName(enum GP_DataType type)
443 switch (type) {
444 case GP_DATA_INT:
445 return "Int";
446 case GP_DATA_DOUBLE:
447 return "Double";
448 case GP_DATA_RATIONAL:
449 return "Rational";
450 case GP_DATA_STRING:
451 return "String";
452 case GP_DATA_DICT:
453 return "Dict";
456 return "Invalid";
459 GP_DataNode *GP_DataStorageAddInt(GP_DataStorage *self, GP_DataNode *node,
460 const char *id, long i)
462 GP_DataNode data = {
463 .type = GP_DATA_INT,
464 .id = id,
465 .value.i = i,
468 return GP_DataStorageAdd(self, node, &data);
471 GP_DataNode *GP_DataStorageAddString(GP_DataStorage *self, GP_DataNode *node,
472 const char *id, const char *str)
474 GP_DataNode data = {
475 .type = GP_DATA_STRING,
476 .id = id,
477 .value.str = str,
480 return GP_DataStorageAdd(self, node, &data);
483 GP_DataNode *GP_DataStorageAddDouble(GP_DataStorage *self, GP_DataNode *node,
484 const char *id, double d)
486 GP_DataNode data = {
487 .type = GP_DATA_DOUBLE,
488 .id = id,
489 .value.d = d,
492 return GP_DataStorageAdd(self, node, &data);
495 GP_DataNode *GP_DataStorageAddRational(GP_DataStorage *self, GP_DataNode *node,
496 const char *id, long num, long den)
498 GP_DataNode data = {
499 .type = GP_DATA_RATIONAL,
500 .id = id,
501 .value.rat = {.num = num, .den = den},
504 return GP_DataStorageAdd(self, node, &data);
507 GP_DataNode *GP_DataStorageAddDict(GP_DataStorage *self, GP_DataNode *node,
508 const char *id)
510 GP_DataNode data = {
511 .type = GP_DATA_DICT,
512 .id = id,
515 return GP_DataStorageAdd(self, node, &data);