diff src/metadata.c @ 1238:947e603a52c6

simplified metadata interface, dropped metadata_read, fixes for older exiv2 versions
author nadvornik
date Sat, 10 Jan 2009 20:40:37 +0000
parents 31f50c1b6a9a
children 30e207ac22e4
line wrap: on
line diff
--- a/src/metadata.c	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/metadata.c	Sat Jan 10 20:40:37 2009 +0000
@@ -325,7 +325,15 @@
 	
 	fclose(f);
 
-	*keywords = g_list_reverse(list);
+	if (keywords) 
+		{
+		*keywords = g_list_reverse(list);
+		}
+	else
+		{
+		string_list_free(list);
+		}
+		
 	if (comment_build)
 		{
 		if (comment)
@@ -420,209 +428,93 @@
 	return g_list_reverse(newlist);
 }
 
-
-static gint metadata_xmp_read(FileData *fd, GList **keywords, gchar **comment)
+GList *metadata_read_list(FileData *fd, const gchar *key)
 {
 	ExifData *exif;
+	GList *list = NULL;
+	if (!fd) return NULL;
 
-	exif = exif_read_fd(fd);
-	if (!exif) return FALSE;
-
-	if (comment)
+	/* unwritten data overide everything */
+	if (fd->modified_xmp)
 		{
-		gchar *text;
-		ExifItem *item = exif_get_item(exif, COMMENT_KEY);
-
-		text = exif_item_get_string(item, 0);
-		*comment = utf8_validate_or_convert(text);
-		g_free(text);
+	        list = g_hash_table_lookup(fd->modified_xmp, key);
+		if (list) return string_list_copy(list);
 		}
 
-	if (keywords)
+	/* 
+	    Legacy metadata file is the primary source if it exists.
+	    Merging the lists does not make much sense, because the existence of
+	    legacy metadata file indicates that the other metadata sources are not
+	    writable and thus it would not be possible to delete the keywords
+	    that comes from the image file.
+	*/
+	if (strcmp(key, KEYWORD_KEY) == 0)
 		{
-		ExifItem *item;
-		guint i;
-		
-		*keywords = NULL;
-		item = exif_get_item(exif, KEYWORD_KEY);
-		for (i = 0; i < exif_item_get_elements(item); i++)
-			{
-			gchar *kw = exif_item_get_string(item, i);
-			gchar *utf8_kw;
-
-			if (!kw) break;
-
-			utf8_kw = utf8_validate_or_convert(kw);
-			*keywords = g_list_append(*keywords, (gpointer) utf8_kw);
-			g_free(kw);
-			}
+	        if (metadata_legacy_read(fd, &list, NULL)) return list;
+	        }
 
-		/* FIXME:
-		 * Exiv2 handles Iptc keywords as multiple entries with the
-		 * same key, thus exif_get_item returns only the first keyword
-		 * and the only way to get all keywords is to iterate through
-		 * the item list.
-		 */
-		 /* Read IPTC keywords only if there are no XMP keywords
-		  * IPTC does not have standard charset, thus the encoding may differ
-		  * from XMP and keyword merging is not reliable.
-		  */
-		 if (!*keywords)
-			{
-			for (item = exif_get_first_item(exif);
-			     item;
-			     item = exif_get_next_item(exif))
-				{
-				guint tag;
-			
-				tag = exif_item_get_tag_id(item);
-				if (tag == 0x0019)
-					{
-					gchar *tag_name = exif_item_get_tag_name(item);
-        
-					if (strcmp(tag_name, "Iptc.Application2.Keywords") == 0)
-						{
-						gchar *kw;
-						gchar *utf8_kw;
-        
-						kw = exif_item_get_data_as_text(item);
-						if (!kw) continue;
-        
-						utf8_kw = utf8_validate_or_convert(kw);
-						*keywords = g_list_append(*keywords, (gpointer) utf8_kw);
-						g_free(kw);
-						}
-					g_free(tag_name);
-					}
-				}
-			}
-		}
-
+	if (strcmp(key, COMMENT_KEY) == 0)
+		{
+		gchar *comment = NULL;
+	        if (metadata_legacy_read(fd, NULL, &comment)) return g_list_append(NULL, comment);
+	        }
+	
+	exif = exif_read_fd(fd); /* this is cached, thus inexpensive */
+	if (!exif) return NULL;
+	list = exif_get_metadata(exif, key);
 	exif_free_fd(fd, exif);
-
-	return (comment && *comment) || (keywords && *keywords);
+	return list;
 }
 
-gint metadata_read(FileData *fd, GList **keywords, gchar **comment)
+gchar *metadata_read_string(FileData *fd, const gchar *key)
 {
-	GList *keywords_xmp = NULL;
-	GList *keywords_legacy = NULL;
-	gchar *comment_xmp = NULL;
-	gchar *comment_legacy = NULL;
-	gint result_xmp, result_legacy;
-
-	if (!fd) return FALSE;
-
-	result_xmp = metadata_xmp_read(fd, &keywords_xmp, &comment_xmp);
-	result_legacy = metadata_legacy_read(fd, &keywords_legacy, &comment_legacy);
-
-	if (!result_xmp && !result_legacy)
+	GList *string_list = metadata_read_list(fd, key);
+	if (string_list)
 		{
-		return FALSE;
+		gchar *str = string_list->data;
+		string_list->data = NULL;
+		string_list_free(string_list);
+		return str;
 		}
-
-	if (keywords)
+	return NULL;
+}
+	
+gboolean metadata_append_string(FileData *fd, const gchar *key, const char *value)
+{
+	gchar *str = metadata_read_string(fd, key);
+	
+	if (!str) 
 		{
-		if (result_xmp && result_legacy)
-			*keywords = g_list_concat(keywords_xmp, keywords_legacy);
-		else
-			*keywords = result_xmp ? keywords_xmp : keywords_legacy;
-
-		*keywords = remove_duplicate_strings_from_list(*keywords);
+		return metadata_write_string(fd, key, value);
 		}
 	else
 		{
-		if (result_xmp) string_list_free(keywords_xmp);
-		if (result_legacy) string_list_free(keywords_legacy);
-		}
-
-
-	if (comment)
-		{
-		if (result_xmp && result_legacy && comment_xmp && comment_legacy && *comment_xmp && *comment_legacy)
-			*comment = g_strdup_printf("%s\n%s", comment_xmp, comment_legacy);
-		else
-			*comment = result_xmp ? comment_xmp : comment_legacy;
+		gchar *new_string = g_strconcat(str, value, NULL);
+		gboolean ret = metadata_write_string(fd, key, new_string);
+		g_free(str);
+		g_free(new_string);
+		return ret;
 		}
-
-	if (result_xmp && (!comment || *comment != comment_xmp)) g_free(comment_xmp);
-	if (result_legacy && (!comment || *comment != comment_legacy)) g_free(comment_legacy);
-	
-	// return FALSE in the following cases:
-	//  - only looking for a comment and didn't find one
-	//  - only looking for keywords and didn't find any
-	//  - looking for either a comment or keywords, but found nothing
-	if ((!keywords && comment   && !*comment)  ||
-	    (!comment  && keywords  && !*keywords) ||
-	    ( comment  && !*comment &&   keywords && !*keywords))
-		return FALSE;
-
-	return TRUE;
 }
 
-void metadata_set(FileData *fd, GList *new_keywords, gchar *new_comment, gboolean append)
+gboolean metadata_append_list(FileData *fd, const gchar *key, const GList *values)
 {
-	gchar *comment = NULL;
-	GList *keywords = NULL;
-	GList *keywords_list = NULL;
-
-	metadata_read(fd, &keywords, &comment);
+	GList *list = metadata_read_list(fd, key);
 	
-	if (new_comment)
-		{
-		if (append && comment && *comment)
-			{
-			gchar *tmp = comment;
-				
-			comment = g_strconcat(tmp, new_comment, NULL);
-			g_free(tmp);
-			}
-		else
-			{
-			g_free(comment);
-			comment = g_strdup(new_comment);
-			}
-		}
-	
-	if (new_keywords)
+	if (!list) 
 		{
-		if (append && keywords && g_list_length(keywords) > 0)
-			{
-			GList *work;
-
-			work = new_keywords;
-			while (work)
-				{
-				gchar *key;
-				GList *p;
-
-				key = work->data;
-				work = work->next;
-
-				p = keywords;
-				while (p && key)
-					{
-					gchar *needle = p->data;
-					p = p->next;
-
-					if (strcmp(needle, key) == 0) key = NULL;
-					}
-
-				if (key) keywords = g_list_append(keywords, g_strdup(key));
-				}
-			keywords_list = keywords;
-			}
-		else
-			{
-			keywords_list = new_keywords;
-			}
+		return metadata_write_list(fd, key, values);
 		}
-	
-	metadata_write_string(fd, COMMENT_KEY, comment);
-	metadata_write_list(fd, KEYWORD_KEY, keywords);
-
-	string_list_free(keywords);
-	g_free(comment);
+	else
+		{
+		gboolean ret;
+		list = g_list_concat(list, string_list_copy(values));
+		list = remove_duplicate_strings_from_list(list);
+		
+		ret = metadata_write_list(fd, key, list);
+		string_list_free(list);
+		return ret;
+		}
 }
 
 gboolean find_string_in_list(GList *list, const gchar *string)
@@ -687,7 +579,8 @@
 {
 	GList *keywords;
 	gboolean found = FALSE;
-	if (metadata_read(fd, &keywords, NULL))
+	keywords = metadata_read_list(fd, KEYWORD_KEY);
+	if (keywords)
 		{
 		GList *work = keywords;
 
@@ -713,7 +606,7 @@
 	gboolean found = FALSE;
 	gboolean changed = FALSE;
 	GList *work;
-	metadata_read(fd, &keywords, NULL);
+	keywords = metadata_read_list(fd, KEYWORD_KEY);
 
 	work = keywords;