X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=libexif%2Fexif-content.c;h=6d6c589d07b89fc42c994d6b2ef1c0d0e53b7486;hb=18fd0ff7408961416a3077071320d95c66873b5d;hp=2589fcfc046f251352a6487d1ad02ac8d9a864d5;hpb=098e618840f91af4a54a4aaaf86a624e25adad64;p=platform%2Fupstream%2Flibexif.git diff --git a/libexif/exif-content.c b/libexif/exif-content.c index 2589fcf..6d6c589 100644 --- a/libexif/exif-content.c +++ b/libexif/exif-content.c @@ -1,106 +1,78 @@ /* exif-content.c * - * Copyright (C) 2001 Lutz Müller + * Copyright (c) 2001 Lutz Mueller * * This library 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 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of + * This library 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. + * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. */ + #include -#include "exif-content.h" + +#include +#include #include #include #include -#include - -//#define DEBUG - -static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; - -typedef struct _ExifContentNotifyData ExifContentNotifyData; -struct _ExifContentNotifyData { - ExifContentEvent events; - ExifContentNotifyFunc func; - void *data; -}; +/* unused constant + * static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; + */ struct _ExifContentPrivate { - ExifContentNotifyData *notifications; - unsigned int count; - unsigned int ref_count; + + ExifMem *mem; + ExifLog *log; }; -unsigned int -exif_content_add_notify (ExifContent *content, ExifContentEvent events, - ExifContentNotifyFunc func, void *data) +ExifContent * +exif_content_new (void) { - if (!content) - return (0); - - if (!content->priv->notifications) - content->priv->notifications = - malloc (sizeof (ExifContentNotifyData)); - else - content->priv->notifications = - realloc (content->priv->notifications, - sizeof (ExifContentNotifyData) * - (content->priv->count + 1)); - content->priv->notifications[content->priv->count].events = events; - content->priv->notifications[content->priv->count].func = func; - content->priv->notifications[content->priv->count].data = data; - content->priv->count++; - - return (content->priv->count); -} + ExifMem *mem = exif_mem_new_default (); + ExifContent *content = exif_content_new_mem (mem); -void -exif_content_remove_notify (ExifContent *content, unsigned int id) -{ - if (!content) - return; - if (id > content->priv->count) - return; + exif_mem_unref (mem); - memmove (content->priv->notifications + id - 1, - content->priv->notifications + id, - sizeof (ExifContentNotifyData) * - (content->priv->count - id)); - content->priv->count--; + return content; } ExifContent * -exif_content_new (void) +exif_content_new_mem (ExifMem *mem) { ExifContent *content; - content = malloc (sizeof (ExifContent)); + if (!mem) return NULL; + + content = exif_mem_alloc (mem, (ExifLong) sizeof (ExifContent)); if (!content) - return (NULL); - memset (content, 0, sizeof (ExifContent)); - content->priv = malloc (sizeof (ExifContentPrivate)); + return NULL; + content->priv = exif_mem_alloc (mem, + (ExifLong) sizeof (ExifContentPrivate)); if (!content->priv) { - free (content); - return (NULL); + exif_mem_free (mem, content); + return NULL; } - memset (content->priv, 0, sizeof (ExifContentPrivate)); + content->priv->ref_count = 1; - return (content); + content->priv->mem = mem; + exif_mem_ref (mem); + + return content; } void @@ -120,44 +92,22 @@ exif_content_unref (ExifContent *content) void exif_content_free (ExifContent *content) { + ExifMem *mem = (content && content->priv) ? content->priv->mem : NULL; unsigned int i; + if (!content) return; + for (i = 0; i < content->count; i++) exif_entry_unref (content->entries[i]); - free (content->entries); - free (content->priv); - free (content); -} - -void -exif_content_parse (ExifContent *content, const unsigned char *data, - unsigned int size, unsigned int offset, - ExifByteOrder order) -{ - unsigned int i; - ExifShort n; - ExifEntry *entry; - - if (!content) - return; + exif_mem_free (mem, content->entries); - content->order = order; - - /* Read number of entries */ - if (size < offset + 2) - return; - n = exif_get_short (data + offset, order); -#ifdef DEBUG - printf ("Parsing directory with %i entries...\n", n); -#endif - - for (i = 0; i < n; i++) { - entry = exif_entry_new (); - exif_content_add_entry (content, entry); - exif_entry_parse (content->entries[i], data, size, - offset + 2 + 12 * i, order); - exif_entry_unref (entry); + if (content->priv) { + exif_log_unref (content->priv->log); } + + exif_mem_free (mem, content->priv); + exif_mem_free (mem, content); + exif_mem_unref (mem); } void @@ -173,74 +123,205 @@ exif_content_dump (ExifContent *content, unsigned int indent) if (!content) return; - printf ("%sDumping exif content (%i entries)...\n", buf, + printf ("%sDumping exif content (%u entries)...\n", buf, content->count); for (i = 0; i < content->count; i++) exif_entry_dump (content->entries[i], indent + 1); } -static void -exif_content_notify (ExifContent *content, ExifEntry *entry, - ExifContentEvent event) +void +exif_content_add_entry (ExifContent *c, ExifEntry *entry) { - unsigned int i; + ExifEntry **entries; + if (!c || !c->priv || !entry || entry->parent) return; + + /* One tag can only be added once to an IFD. */ + if (exif_content_get_entry (c, entry->tag)) { + exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "ExifContent", + "An attempt has been made to add " + "the tag '%s' twice to an IFD. This is against " + "specification.", exif_tag_get_name (entry->tag)); + return; + } - for (i = 0; i < content->priv->count; i++) - if (content->priv->notifications[i].events & event) - content->priv->notifications[i].func (content, entry, - content->priv->notifications[i].data); + entries = exif_mem_realloc (c->priv->mem, + c->entries, sizeof (ExifEntry*) * (c->count + 1)); + if (!entries) return; + entry->parent = c; + entries[c->count++] = entry; + c->entries = entries; + exif_entry_ref (entry); } void -exif_content_add_entry (ExifContent *content, ExifEntry *entry) +exif_content_remove_entry (ExifContent *c, ExifEntry *e) { - if (entry->parent) - return; + unsigned int i; + ExifEntry **t, *temp; + + if (!c || !c->priv || !e || (e->parent != c)) return; + + /* Search the entry */ + for (i = 0; i < c->count; i++) + if (c->entries[i] == e) + break; + + if (i == c->count) + return; + + /* Remove the entry */ + temp = c->entries[c->count-1]; + if (c->count > 1) { + t = exif_mem_realloc (c->priv->mem, c->entries, + sizeof(ExifEntry*) * (c->count - 1)); + if (!t) { + return; + } + c->entries = t; + c->count--; + if (i != c->count) { /* we deallocated the last slot already */ + memmove (&t[i], &t[i + 1], sizeof (ExifEntry*) * (c->count - i - 1)); + t[c->count-1] = temp; + } + } else { + exif_mem_free (c->priv->mem, c->entries); + c->entries = NULL; + c->count = 0; + } + e->parent = NULL; + exif_entry_unref (e); +} - entry->parent = content; - content->entries = realloc (content->entries, - sizeof (ExifEntry) * (content->count + 1)); - content->entries[content->count] = entry; - exif_entry_ref (entry); - content->count++; +ExifEntry * +exif_content_get_entry (ExifContent *content, ExifTag tag) +{ + unsigned int i; + + if (!content) + return (NULL); - exif_content_notify (content, entry, EXIF_CONTENT_EVENT_ADD); + for (i = 0; i < content->count; i++) + if (content->entries[i]->tag == tag) + return (content->entries[i]); + return (NULL); } void -exif_content_remove_entry (ExifContent *content, ExifEntry *entry) +exif_content_foreach_entry (ExifContent *content, + ExifContentForeachEntryFunc func, void *data) { unsigned int i; - if (entry->parent != content) + if (!content || !func) return; for (i = 0; i < content->count; i++) - if (content->entries[i] == entry) - break; - if (i == content->count) + func (content->entries[i], data); +} + +void +exif_content_log (ExifContent *content, ExifLog *log) +{ + if (!content || !content->priv || !log || content->priv->log == log) return; - memmove (&content->entries[i], &content->entries[i + 1], - sizeof (ExifEntry) * (content->count - i - 1)); - content->count--; + if (content->priv->log) exif_log_unref (content->priv->log); + content->priv->log = log; + exif_log_ref (log); +} - exif_content_notify (content, entry, EXIF_CONTENT_EVENT_REMOVE); +ExifIfd +exif_content_get_ifd (ExifContent *c) +{ + if (!c || !c->parent) return EXIF_IFD_COUNT; + + return + ((c)->parent->ifd[EXIF_IFD_EXIF] == (c)) ? EXIF_IFD_EXIF : + ((c)->parent->ifd[EXIF_IFD_0] == (c)) ? EXIF_IFD_0 : + ((c)->parent->ifd[EXIF_IFD_1] == (c)) ? EXIF_IFD_1 : + ((c)->parent->ifd[EXIF_IFD_GPS] == (c)) ? EXIF_IFD_GPS : + ((c)->parent->ifd[EXIF_IFD_INTEROPERABILITY] == (c)) ? EXIF_IFD_INTEROPERABILITY : + EXIF_IFD_COUNT; +} - entry->parent = NULL; - exif_entry_unref (entry); +static void +fix_func (ExifEntry *e, void *UNUSED(data)) +{ + exif_entry_fix (e); } -ExifEntry * -exif_content_get_entry (ExifContent *content, ExifTag tag) +/*! + * Check if this entry is unknown and if so, delete it. + * \note Be careful calling this function in a loop. Deleting an entry from + * an ExifContent changes the index of subsequent entries, as well as the + * total size of the entries array. + */ +static void +remove_not_recorded (ExifEntry *e, void *UNUSED(data)) { - unsigned int i; + ExifIfd ifd = exif_entry_get_ifd(e) ; + ExifContent *c = e->parent; + ExifDataType dt = exif_data_get_data_type (c->parent); + ExifTag t = e->tag; + + if (exif_tag_get_support_level_in_ifd (t, ifd, dt) == + EXIF_SUPPORT_LEVEL_NOT_RECORDED) { + exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "exif-content", + "Tag 0x%04x is not recorded in IFD '%s' and has therefore been " + "removed.", t, exif_ifd_get_name (ifd)); + exif_content_remove_entry (c, e); + } - if (!content) - return (NULL); +} - for (i = 0; i < content->count; i++) - if (content->entries[i]->tag == tag) - return (content->entries[i]); - return (NULL); +void +exif_content_fix (ExifContent *c) +{ + ExifIfd ifd = exif_content_get_ifd (c); + ExifDataType dt; + ExifEntry *e; + unsigned int i, num; + + if (!c) + return; + + dt = exif_data_get_data_type (c->parent); + + /* + * First of all, fix all existing entries. + */ + exif_content_foreach_entry (c, fix_func, NULL); + + /* + * Go through each tag and if it's not recorded, remove it. If one + * is removed, exif_content_foreach_entry() will skip the next entry, + * so if this happens do the loop again from the beginning to ensure + * they're all checked. This could be avoided if we stop relying on + * exif_content_foreach_entry but loop intelligently here. + */ + do { + num = c->count; + exif_content_foreach_entry (c, remove_not_recorded, NULL); + } while (num != c->count); + + /* + * Then check for non-existing mandatory tags and create them if needed + */ + num = exif_tag_table_count(); + for (i = 0; i < num; ++i) { + const ExifTag t = exif_tag_table_get_tag (i); + if (exif_tag_get_support_level_in_ifd (t, ifd, dt) == + EXIF_SUPPORT_LEVEL_MANDATORY) { + if (exif_content_get_entry (c, t)) + /* This tag already exists */ + continue; + exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "exif-content", + "Tag '%s' is mandatory in IFD '%s' and has therefore been added.", + exif_tag_get_name_in_ifd (t, ifd), exif_ifd_get_name (ifd)); + e = exif_entry_new (); + exif_content_add_entry (c, e); + exif_entry_initialize (e, t); + exif_entry_unref (e); + } + } }