From 5d07526c70845eae42935de4a03ec9d90bf8a019 Mon Sep 17 00:00:00 2001 From: Cyril Hrubis Date: Sun, 27 May 2012 22:11:45 +0200 Subject: [PATCH] loaders: Create generic metadata storage. --- demos/c_simple/Makefile | 2 +- include/loaders/GP_Loaders.h | 2 + include/loaders/GP_MetaData.h | 103 +++++++++++++++++ libs/loaders/GP_MetaData.c | 258 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 include/loaders/GP_MetaData.h create mode 100644 libs/loaders/GP_MetaData.c diff --git a/demos/c_simple/Makefile b/demos/c_simple/Makefile index eeadcf87..72048314 100644 --- a/demos/c_simple/Makefile +++ b/demos/c_simple/Makefile @@ -6,7 +6,7 @@ INCLUDE= LDLIBS+=-lGP -lGP_backends -lSDL -L$(TOPDIR)/build/ APPS=backend_example loaders_example loaders filters_symmetry gfx_koch\ - virtual_backend_example + virtual_backend_example meta_data include $(TOPDIR)/pre.mk include $(TOPDIR)/app.mk diff --git a/include/loaders/GP_Loaders.h b/include/loaders/GP_Loaders.h index 38633c7e..d374f996 100644 --- a/include/loaders/GP_Loaders.h +++ b/include/loaders/GP_Loaders.h @@ -44,6 +44,8 @@ #include "GP_JPG.h" #include "GP_GIF.h" +#include "GP_MetaData.h" + /* * Tries to load image accordingly to the file extension. * diff --git a/include/loaders/GP_MetaData.h b/include/loaders/GP_MetaData.h new file mode 100644 index 00000000..2820ee08 --- /dev/null +++ b/include/loaders/GP_MetaData.h @@ -0,0 +1,103 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2012 Cyril Hrubis * + * * + *****************************************************************************/ + +#ifndef LOADERS_METADATA_H +#define LOADERS_METADATA_H + +#define GP_META_RECORD_ID_MAX 16 + +enum GP_MetaType { + GP_META_INT, + GP_META_STRING, +}; + +union GP_MetaValue { + int i; + const char *str; +}; + +typedef struct GP_MetaRecord { + char id[GP_META_RECORD_ID_MAX]; + unsigned int hash; + enum GP_MetaType type; + struct GP_MetaRecord *next; + union GP_MetaValue val; +} GP_MetaRecord; + +typedef struct GP_MetaData GP_MetaData; + +/* + * Creates a metadata storage for at least expected_records values. + * + * Returns NULL if allocation has failed. + */ +GP_MetaData *GP_MetaDataCreate(unsigned int expected_records); + +/* + * Destroys metadata (frees all alocated memory). + */ +void GP_MetaDataDestroy(GP_MetaData *self); + +/* + * Prints metadata into the stdout. + */ +void GP_MetaDataPrint(GP_MetaData *self); + +/* + * Looks for metadata record with id. + */ +GP_MetaRecord *GP_MetaDataGetRecord(GP_MetaData *self, const char *id); + +/* + * Looks for integer metadata with id. Returns 0 on success and res is set to + * found metadata value. + */ +int GP_MetaDataGetInt(GP_MetaData *self, const char *id, int *res); + +/* + * Looks for string metadata by id. Returns pointe to found string, or NULL if + * there was no such value. + */ +const char *GP_MetaDataGetString(GP_MetaData *self, const char *id); + +/* + * Creates an record and returns pointer to it. + * + * May return NULL if allocation has failed. + */ +GP_MetaRecord *GP_MetaDataCreateRecord(GP_MetaData *self, const char *id); + +/* + * Creates an integer record and returns pointer to it. + */ +GP_MetaRecord *GP_MetaDataCreateInt(GP_MetaData *self, const char *id, int val); + +/* + * Creates an string record and returns pointer to it. + * + * If dup is set to 1, the string is duplicated inside of the MetaData + * structure, otherwise only the pointer is saved. + */ +GP_MetaRecord *GP_MetaDataCreateString(GP_MetaData *self, const char *id, + const char *str, int dup); + +#endif /* LOADERS_GP_METADATA_H */ diff --git a/libs/loaders/GP_MetaData.c b/libs/loaders/GP_MetaData.c new file mode 100644 index 00000000..b0fcdf87 --- /dev/null +++ b/libs/loaders/GP_MetaData.c @@ -0,0 +1,258 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2012 Cyril Hrubis * + * * + *****************************************************************************/ + +#include +#include + +#include "core/GP_Debug.h" + +#include "GP_MetaData.h" + +struct GP_MetaData { + struct GP_MetaRecord *root; + unsigned int rec_count; + size_t size; + size_t free; + char buf[]; +}; + +static unsigned int do_hash(const char *id) +{ + unsigned int hash = 0; + + while (*id != '\0') { + hash += *id * 1217; + hash %= 46309; + id += 1; + } + + return hash; +} + +GP_MetaData *GP_MetaDataCreate(unsigned int expected_records) +{ + GP_MetaData *data; + size_t size = expected_records * sizeof(struct GP_MetaRecord); + + GP_DEBUG(1, "Creating MetaData for %u records", expected_records); + + data = malloc(sizeof(struct GP_MetaData) + size); + + if (data == NULL) { + GP_DEBUG(1, "Malloc failed :("); + return NULL; + } + + data->root = NULL; + data->rec_count = 0; + data->size = size; + data->free = size; + + return data; +} + +void GP_MetaDataDestroy(GP_MetaData *self) +{ + GP_DEBUG(1, "Destroying MetaData %p", self); + free(self); +} + +void GP_MetaDataPrint(GP_MetaData *self) +{ + GP_MetaRecord *rec; + + printf("MetaData %u record(s)\n", self->rec_count); + + for (rec = self->root; rec != NULL; rec = rec->next) { + printf("%-16s: ", rec->id); + + switch (rec->type) { + case GP_META_INT: + printf("%i\n", rec->val.i); + break; + case GP_META_STRING: + printf("'%s'\n", rec->val.str); + break; + } + } +} + +static GP_MetaRecord *record_lookup(GP_MetaData *self, const char *id, + unsigned int hash) +{ + GP_MetaRecord *rec; + + for (rec = self->root; rec != NULL; rec = rec->next) + if (rec->hash == hash && !strcmp(rec->id, id)) + return rec; + + return NULL; +} + +static void *do_alloc(struct GP_MetaData *self, size_t size) +{ + if (self->free < size) { + GP_DEBUG(0, "TODO: storage full"); + return NULL; + } + + void *ret = ((char*)self) + sizeof(struct GP_MetaData) + (self->size - self->free); + + self->free -= size; + + return ret; +} + +static GP_MetaRecord *record_create(GP_MetaData *self, const char *id, + unsigned int hash) +{ + GP_MetaRecord *rec; + + if (strlen(id) + 1 > GP_META_RECORD_ID_MAX) { + GP_DEBUG(0, "Can't create id '%s' longer than %i chars", + id, GP_META_RECORD_ID_MAX - 1); + return NULL; + } + + rec = do_alloc(self, sizeof(struct GP_MetaRecord)); + + if (rec == NULL) + return NULL; + + strcpy(rec->id, id); + rec->hash = hash; + rec->next = self->root; + self->root = rec; + + self->rec_count++; + + return rec; +} + +GP_MetaRecord *GP_MetaDataCreateRecord(GP_MetaData *self, const char *id) +{ + unsigned int hash = do_hash(id); + + if (record_lookup(self, id, hash)) { + GP_DEBUG(1, "Trying to create duplicate record id '%s'", id); + return NULL; + } + + return record_create(self, id, hash); +} + +int GP_MetaDataGetInt(GP_MetaData *self, const char *id, int *res) +{ + GP_MetaRecord *rec; + + GP_DEBUG(2, "Looking for GP_META_INT id '%s'", id); + + rec = record_lookup(self, id, do_hash(id)); + + if (rec == NULL) { + GP_DEBUG(3, "Record id '%s' not found", id); + return 1; + } + + if (rec->type != GP_META_INT) { + GP_DEBUG(3, "Record id '%s' has wrong type", id); + return 1; + } + + *res = rec->val.i; + + GP_DEBUG(3, "Found GP_META_INT id '%s' = %i", id, *res); + + return 0; +} + +const char *GP_MetaDataGetString(GP_MetaData *self, const char *id) +{ + GP_MetaRecord *rec; + + GP_DEBUG(2, "Looking for GP_META_STRING id '%s'", id); + + rec = record_lookup(self, id, do_hash(id)); + + if (rec == NULL) { + GP_DEBUG(3, "Record id '%s' not found", id); + return NULL; + } + + if (rec->type != GP_META_STRING) { + GP_DEBUG(3, "Record id '%s' has wrong type", id); + return NULL; + } + + GP_DEBUG(3, "Found GP_META_STRING id '%s' = '%s'", id, rec->val.str); + + return rec->val.str; +} + +GP_MetaRecord *GP_MetaDataCreateInt(GP_MetaData *self, const char *id, int val) +{ + GP_MetaRecord *rec; + + GP_DEBUG(2, "Creating GP_META_INT id '%s' = %i", id, val); + + rec = GP_MetaDataCreateRecord(self, id); + + if (rec == NULL) + return NULL; + + rec->type = GP_META_INT; + rec->val.i = val; + + return rec; +} + +GP_MetaRecord *GP_MetaDataCreateString(GP_MetaData *self, const char *id, + const char *str, int dup) +{ + GP_MetaRecord *rec; + + GP_DEBUG(2, "Creating GP_META_STRING id '%s' = '%s'", id, str); + + rec = GP_MetaDataCreateRecord(self, id); + + if (rec == NULL) + return NULL; + + if (dup) { + size_t size = strlen(str) + 1; + char *s; + + /* Play safe with aligment */ + if (size % 8) + size += 8 - size % 8; + + //TODO: allocation error + s = do_alloc(self, size); + strcpy(s, str); + str = s; + } + + rec->type = GP_META_STRING; + rec->val.str = str; + + return rec; +} -- 2.11.4.GIT